我对设计模式非常陌生,并且对流式接口和构建器模式之间的区别感到困惑。
我理解流畅接口的概念。但是构建器模式有点令人困惑。我无法理解在 Builder 模式中使用 Director。
我可以同时使用 Builder 模式和 Fluent Interface 吗?如果是这样,那么我应该如何与导演和混凝土建造者一起这样做?
我的问题不是关于建造者模式的优势。但是这个问题的目的是了解构建器模式和流畅界面之间的关系。
使用来自 GoF 的 Builder 的 UML 序列图进行编辑:
我对设计模式非常陌生,并且对流式接口和构建器模式之间的区别感到困惑。
我理解流畅接口的概念。但是构建器模式有点令人困惑。我无法理解在 Builder 模式中使用 Director。
我可以同时使用 Builder 模式和 Fluent Interface 吗?如果是这样,那么我应该如何与导演和混凝土建造者一起这样做?
我的问题不是关于建造者模式的优势。但是这个问题的目的是了解构建器模式和流畅界面之间的关系。
使用来自 GoF 的 Builder 的 UML 序列图进行编辑:
流利的接口是语义门面。您将它们放在现有代码之上,以减少语法噪音并更清楚地表达代码在通用语言中的作用。这是构建内部域特定语言时使用的模式。这是关于可读性。
导演/建造者协调某物的建造。也就是说,如果您正在构建披萨烘焙机,Director 将确保从订单到披萨的步骤由正确的构建者使用正确的数据以正确的顺序执行。这是关于验证和授权的。
您当然可以在 Director/Builder 模式之上放置一个 Fluent Interface 以使其阅读更加流畅,并强调领域概念(相对于构建和委派的技术过程)。那可能是一个表达式生成器。
我想强调 Fluent Interfaces 不仅仅是Method Chaining。这是一个常见的误解。方法链是实现 Fluent 接口的一种方法,但它并不相同,因为它缺乏语义品质,例如,这不是 Fluent 接口:
SomeObject.setFoo(1).setBar(2).setBaz(3);
以上并没有表达关于 SomeObject 的任何内容。它不是某些语义模型之上的外观。这只是一些链接的方法。Fluent Interface 的一个示例是 SQL 查询构建器,例如
SQLBuilder.select('foo').from('bar').where('foo = ?', 42).prepare();
该 API 的底层是创建 SQL 语句的代码。它可能包含多个对象,显示的调用可以很好地创建一个 Select 对象,调用它的 setter,创建一个 Condition 对象并将其应用于 Select 对象,最后返回一个 Statement 对象。但是这一切对我们都是隐藏的。这也突出了 Fluent Interfaces 的另一个方面:它们可能违反SOLID和Demeter 定律。但由于它是代码之上的外观,希望遵循这些设计原则,所以没那么重要,因为您将违规行为定位到 Fluent 接口。
Fluent 接口背后的想法是,可以通过将多个属性用点连接到对象上,而不必每次都重新指定对象。构建器模式背后的想法是,非共享的可变对象通常比非共享的不可变对象更容易使用,但与共享可变对象相比,共享不可变对象更容易推理。因此,代码可以使用一个易于使用的可变对象来生成所需实例的“模型”,然后使用它来制作一个易于共享的、包含相同数据的不可变对象。
这两个想法可以很好地协同工作,但有些正交。
请注意,流畅的界面至少可以通过三种方式工作:
最后一种风格要求采取一些措施来应用所有补丁,但如果要修改的对象很大并且需要进行许多更改,它可以最大限度地减少所需的复制量。