一天一个设计模式 - 建造者模式(Builder)
Posted 零壹技术栈
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一天一个设计模式 - 建造者模式(Builder)相关的知识,希望对你有一定的参考价值。
前言
建造模式是对象的创建模式。建造模式可以将一个产品的内部表象(internal representation
)与产品的生产过程分割开来,从而可以使一个建造过程生成具有不同的内部表象的产品对象。
(一). 产品的内部表象
一个产品常有不同的组成成分作为产品的零件,这些零件有可能是对象,也有可能不是对象,他们通常又称为产品的内部表象(internal representation
)。
(二). 对象性质的建造
有些情况下,一个对象会有些重要的性质,在它们没有正确赋值之前,对象不能作为一个完整的产品使用。比如:一个电子邮件有发件人地址、收件人地址、主题、内容、附件等部分,而在最基本的发件人地址得到赋值之前,这个电子邮件是不可以发送的。
有些情况下,一个对象的有些性质必须按照某个顺序赋值才有意义。在某个性质没有赋值之前,另一个性质则无法赋值。
这些情况使得性质本身的建造设计到复杂的业务逻辑。设置后,此对象相当于一个有待建造的产品,而对象的这些性质相当于产品的零件,建造产品的过程是建造零件的过程。
由于建造零件的过程很复杂,因此,这些零件的建造过程往往被外部化到另一个成为建造者的对象中,建造者对象返还给客户端的是一个全部零件都建造完毕的产品对象。
建造模式利用一个导演者对象和具体建造者对象一个个的建造出所有的零件,从而建造出完整的产品对象。建造者模式将产品的结构和产品的零件的建造过程对客户端隐藏起来,把对建造过程进行指挥的责任和具体建造者零件的责任分割开来,达到责任划分和封装的目的。
正文
建造模式的结构
在这个示意的系统里,最终产品Product
只有两个零件,即part1
和part2
。相应的构造方法也有两个,即buildPart1()
和buildPart2()
。
同时可以看出本模式涉及到四个角色,它们分别为:
抽象建造者(Builder):
给出一个抽象接口,以规范产品对象的各个组成成分的建造。模式中真正创建产品对象的是具体建造者ConcreteBuilder
角色。
具体建造者类必须实现这个接口要求的两种方法:
- 一种是产品具体零件建造方法:
buildPart1()
和buildPart2()
; - 另一种是返回构造完成的产品的方法
retrieveResult()
。
一般来说,产品所包含的零件数目与建造方法的数目相符。换言之,有多少零件需要建造,就会有多少相应的建造方法。
具体建造者(ContreteBuilder):
担任这个角色的是抽象建造者在具体业务场景的下的建造实现。这个角色要完成的任务包括:
- 实现抽象建造者
Builder
所声明的接口,给出一步步完成创建产品实例的操作。 - 在建造过程完成后,提供产品的实例。
导演者(Director):
担任这个角色的类调用具体建造者角色以创建产品对象。应当指出的是,导演者角色并没有产品类的具体知识,真正拥有产品类的具体知识的是具体建造者角色。
产品(Product):
产品便是建造中的复杂对象,一般来说,一个系统中会有多于一个的产品类,而且这些产品类并不一定有共同的接口,而完全可以是不相关联的。
建造模式的示例代码
Product.java
1
|
public class Product {
|
Builder.java
1
|
/**
|
ConcreteBuilder.java
1
|
/**
|
Director.java
1
|
/**
|
Client.java
1
|
public class Client {
|
上述代码完成的具体步骤:
- 客户端创建具体建造者对象;
- 将具体建造者对象交给导演者;
- 导演者操作建造者对象建造产品零件;
- 当产品创建完成后,导演者将产品返回给客户端。
建造者模式构建复杂对象
考虑这样一个实际业务应用,要创建一个保险合同的对象,里面很多属性的值都有约束,要求创建出来的对象是满足这些约束规则的。
约束规则如下:
保险合同通常情况下可以和个人签订,也可以和某个公司签订个,但是一份保险合同不能同时和个人和公司签订。这个对象里有很多类似于这样的约束,采用建造者模式来构建复杂的对象,通常会对建造者模式进行一定的简化,因为目标明确,就是创建某个复杂对象,因此做适当的简化会使得程序更简介。
具体实现思路如下:
- 由于是用
Builder
建造者模式来创建某个对象,因此就没有必要再定义一个Builder
接口,直接提供一个具体的建造类就可以了。 - 对于创建一个复杂的对象,可能会有很多种不同的选择和步骤,干脆去掉导演者
Director
,把导演者的功能和Client
客户端的功能合并起来,也就是说Client
客户端的功能就相当于导演者,它来指导建造者去构建需要的复杂对象。
于是,建造者(Builder
)可以抽象到目标产品(Product
)的内部,这样最大的好处对外屏蔽掉具体的建造实现,是示例代码如下:
InstranceContract.java
1
|
/** |