language-agnostic - 流畅的接口(interface) - 方法链

标签 language-agnostic design-patterns oop fluent-interface

方法链是我所知道的构建流畅接口(interface)的唯一方法。

这是一个 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));
    }

那么其他人如何创建流畅的界面呢?你如何创建它?需要什么语言/平台/技术?

最佳答案

构建流畅界面背后的核心思想之一是可读性 - 阅读代码的人应该能够理解所实现的内容,而不必深入研究实现来澄清细节。

在现代面向对象语言(例如 C#、VB.NET 和 Java)中,方法链接是实现此目的的一种方法,但它不是唯一的技术 - 其他两种技术是工厂类和命名参数。

另请注意,这些技术并不相互排斥 - 目标是最大限度地提高代码的可读性,而不是方法的纯粹性。

方法链

方法链背后的关键见解是永远不要有返回 void 的方法,而是始终返回某个对象,或更常见的是某个接口(interface),以允许进行进一步的调用。

您不一定需要返回调用该方法的同一对象 - 也就是说,您并不总是需要“return this;”。

一个有用的设计技术是创建一个内部类 - 我总是在它们后面加上“Expression”后缀 - 公开流畅的 API,允许配置另一个类。

这有两个优点 - 它将流畅的 API 保留在一处,与类的主要功能隔离,并且(因为它是一个内部类)它可以以其他类无法做到的方式修补主类的内部结构.

您可能想要使用一系列接口(interface)来控制开发人员在给定时间点可以使用哪些方法。

工厂类

有时您想要构建一系列相关对象 - 示例包括 NHibernate Criteria API、Rhino.Mocks 期望约束和 NUnit 2.4 的新语法。

在这两种情况下,您都拥有要存储的实际对象,但为了使它们更容易创建,有工厂类提供静态方法来制造您需要的实例。

例如,在 NUnit 2.4 中您可以编写:

Assert.That( result, Is.EqualTo(4));

“Is”类是一个静态类,充满了工厂方法,这些方法为 NUnit 的评估创建约束。

事实上,为了考虑 float 的舍入误差和其他不精确性,您可以指定测试的精度:

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);

关于language-agnostic - 流畅的接口(interface) - 方法链,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/293353/

相关文章:

design-patterns - 对对象进行版本控制的设计模式有哪些?

c++ - 我们什么时候应该将代码封装为 "Class"?

c# - 堆和堆栈c#上常规类静态类静态方法实例方法和数据成员的内存分配?

language-agnostic - 弱引用的其他用途?

language-agnostic - 基于网络的商业应用程序的好例子?

language-agnostic - 为什么有些语言有元类?

java - 多个生产者一个消费者的并发

c++ - 如何使用不同线程访问单例类成员函数?

math - float 学有问题吗?

python - 使用属性装饰器时 Python 中的行为不一致