方法链接是我知道构建流畅接口的唯一方法.
这是C#中的一个例子:
John john = new JohnBuilder() .AddSmartCode("c#") .WithfluentInterface("Please") .ButHow("Dunno"); Assert.IsNotNull(john); [Test] public void Should_Assign_Due_Date_With_7DayTermsVia_Invoice_Builder() { DateTime now = DateTime.Now; IInvoice invoice = new InvoiceBuilder() .IssuedOn(now) .WithInvoiceNumber(40) .WithPaymentTerms(PaymentTerms.SevenDays) .Generate(); Assert.IsTrue(invoice.DateDue == now.AddDays(7)); }
那么其他人如何创建流畅的界面.你是如何创造它的?需要什么语言/平台/技术?
构建流畅界面背后的核心思想是可读性 - 阅读代码的人应该能够理解所实现的内容,而无需深入了解实现以澄清细节.
在现代的OO语言中,例如C#,VB.NET和Java,方法链接是实现这一目标的一种方式,但它不是唯一的技术 - 另外两种是工厂类和命名参数.
还要注意,这些技术并不相互排斥 - 目标是最大化代码的可读性,而不是方法的纯度.
方法链接
方法链接背后的关键见解是永远不会有一个返回void的方法,而是总是返回一些对象,或者更常见的是返回一些允许进一步调用的接口.
您不需要返回调用该方法的同一对象 - 也就是说,您并不总是需要"返回此内容".
一个有用的设计技术是创建一个内部类 - 我总是用"表达式"后缀这些 - 它暴露了流畅的API,允许配置另一个类.
这有两个优点 - 它将流畅的API保存在一个地方,与类的主要功能隔离,并且(因为它是一个内部类)它可以修改主类的内部,而其他类则不能.
您可能希望使用一系列接口来控制在给定时间点开发人员可以使用的方法.
工厂类
有时你想建立一系列相关的对象 - 例子包括NHibernate Criteria API,Rhino.Mocks期望约束和NUnit 2.4的新语法.
在这两种情况下,您都拥有要存储的实际对象,但为了使它们更容易创建,工厂类提供了静态方法来制造您需要的实例.
例如,在NUnit 2.4中,您可以编写:
Assert.That( result, Is.EqualTo(4));
"Is"类是一个充满工厂方法的静态类,它为NUnit的评估创建约束.
实际上,为了允许舍入误差和浮点数的其他不精确,您可以为测试指定精度:
Assert.That( result, Is.EqualTo(4.0).Within(0.01));
(提前道歉 - 我的语法可能会关闭.)
命名参数
在支持它们的语言(包括Smalltalk和C#4.0)中,命名参数提供了一种在方法调用中包含额外"语法"的方法,从而提高了可读性.
考虑一个假设的Save()方法,该方法采用文件名,并在保存后应用于该文件的权限:
myDocument.Save("sampleFile.txt", FilePermissions.ReadOnly);
使用命名参数,此方法可能如下所示:
myDocument.Save(file:"SampleFile.txt", permissions:FilePermissions.ReadOnly);
或者,更流利:
myDocument.Save(toFile:"SampleFile.txt", withPermissions:FilePermissions.ReadOnly);
您可以在任何.NET版本或任何其他面向对象的语言中创建流畅的界面.您需要做的就是创建一个对象,其方法始终返回对象本身.
例如在C#中:
public class JohnBuilder { public JohnBuilder AddSmartCode(string s) { // do something return this; } public JohnBuilder WithfluentInterface(string s) { // do something return this; } public JohnBuilder ButHow(string s) { // do something return this; } }
用法:
John = new JohnBuilder() .AddSmartCode("c#") .WithfluentInterface("Please") .ButHow("Dunno");
AFAIK,术语流畅的界面并未指定特定的技术或框架,而是指定设计模式.维基百科在C♯中有一个广泛的流畅接口示例.
在一个简单的setter方法,你不回void
,但this
.这样,您可以链接该对象上的所有语句,其行为类似.以下是基于原始问题的简单示例:
public class JohnBuilder { private IListlanguages = new List (); private IList fluentInterfaces = new List (); private string butHow = string.Empty; public JohnBuilder AddSmartCode(string language) { this.languages.Add(language); return this; } public JohnBuilder WithFluentInterface(string fluentInterface) { this.fluentInterfaces.Add(fluentInterface); return this; } public JohnBuilder ButHow(string butHow) { this.butHow = butHow; return this; } } public static class MyProgram { public static void Main(string[] args) { JohnBuilder johnBuilder = new JohnBuilder().AddSmartCode("c#").WithFluentInterface("Please").ButHow("Dunno"); } }
前段时间我对你现在的怀疑有同样的疑问.我做了一些研究,现在我正在撰写一系列关于设计流畅界面的技术的博客文章.
请查看:
C#第1部分中流畅的界面设计指南
我有一个关于Chaining X Nesting的部分,对你来说很有趣.
在以下文章中,我将以更深入的方式讨论它.
最好的祝福,
AndréVianna