建造者模式(Builder)
定义
Separate the construction of a complex object from its representation so that the sameconstruction process can create different representations.
(将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。)
说明
建造者模式的主要任务是将一个复杂对象的创建过程与他的表示分离,使同样的建造过程可以创建不同的表示。它是将一个复杂的对象分解成一系列小对象,一步步分别创建。一个builder类会一步一步创建一个大而复杂的对象,并且它的创建过程与业务是分离的,完全独立于其他对象。与工厂模式相较建造者模式更注重复杂对象构建的顺序和零散对象的类型,而工厂模式更注重零散对象的创建过程,二者可以结合使用。
建造者模式官方类图:
图中的具体细节:
在建造者模式中如果只有一个建造者并且可以很明确在将来的业务中也不会扩展出其他建造者,那么此时模型中的抽象建造者就可以去掉了,只需要保留一个具体建造者即可。
如果建造的过程只有一种情况,那么可以将模型中的指挥者的工作集成到具体建造者中,让concreateBuilder即担任指挥者的角色又担任建造者的角色, 此时建造者模式基本退化成了工厂方法模式,但又不能认为完全相同,因为两种模式的关注点一开始已经注定不同。这种裁剪的方式表面上看违背了设计模式的理念,但在开发中是经常用到的,有利于减少类文件的数量。比如java中lomnok实现的@builder注解。
设计模式可以作为开发中的辅助工具,学会灵活运用,切不可强制套用。我们的目的是让系统实现快速交付,具体生产中还是怎样方便怎样做。
结构
包含的角色:
Builder : 建造者接口或抽象类 一般它规定了建造时所需要的原材料类型
ConcreteBuilder : 具体建造者 实现了Builder并且能够根据Builder中规定的类型返回具体的材料对象
Product : 产品类 通常实现了模板方法模式的类
Director : 指挥者 负责算法部分,通过安排建造者的执行过程顺序,协调具体建造者中的材料,创建出最终的复杂对象
各模块之间的调用关系如图:
建造者模式的优势
- 使用建造者模式使客户端不必考虑产品的实现细节,通过直接调用的方式产生产品,隐藏了重要代码,使构建与表示分离,体现出系统具有很好的封装性。(封装性)
- 各个具体建造者与建造者之间或指挥者与指挥者之间相互独立,增加新的建造者或扩展算法都不会对其他建造者或指挥者产生影响,从而使系统具有很好的扩展性。(扩展性)
- 由于各个建造者是独立的,因此可以对建造过程进行细化,而不会对其他模块产生影响。(易维护)
建造者模式的应用
- 当构造过程必须按照一定的严格顺序执行时。
构建一个超复杂对象时,大对象一般是由一系列小对象按照一定的顺序严格执行。无论小对象如何变化都不会影响整体的构建顺序,从而实现变与不变分离。类似于将大象关进冰箱需要三步,打开冰箱门,将大象推进去,关闭冰箱门,哪一步处理不好都会出问题。不妨把这个创建的顺序看作一种复杂的算法,一般情况下算法是不会改变的,改变的只是构建它的表示,构建它的表示不同最后产生的效果也一定不相同。比如我们把大象换成了长颈鹿,长颈鹿在冰箱里和大象在冰箱里一定是两种不同的表现形式。
- 当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时。
算法固定是建造者常见的使用场景,另一种场景是算法不同而资源固定的,此时也许就会出现多个指挥者,不同的指挥者代表不同的逻辑算法。比如计算机是由 CPU、主板、内存、硬盘、显卡、机箱、显示器、键盘、鼠标等部件组装而成的,可以考虑多种装配方式,比如是否使用独立显卡,是否使用水冷等情况,用户可以任意选择。此时算法就不再固定,并且最后的效果也不同,从而组装过程可以采用多种方案。
相关模式
抽象工厂模式与建造者模式很像,因为它们都致力于创建复杂对象。主要区别时关注点不同,建造者着重于一步步构造一个复杂对象,而抽象工厂模式着重于构造多种类产品对象(无论简单复杂)。工厂模式的重点在创建,是一个从无到用的过程,而创建者更注重于装配,它的任务是选择合适的小对象通过合适的算法组装出更加复杂的大对象,建造者使用的小对象或零件一定是已经创建完成的。建造者在最后一步返回产品,而抽象工厂在调用的时候就要立刻返回。
组合模式通常用Builder生成。