Builder模式
1、概念
建造者模式是较为复杂的创建型模式,它将客户端与包含多个组成部分(或部件)的复杂对象的创建过程相分离。这个概念有点难懂,其实就是说,客户端你不需要知道复杂对象的内部组成部分和数据的运行结构是什么,你只需要知道Builder这个类型就可以了,它的关注点放在如何一步步创建一个复杂的对象上,而不是把复杂对象一步步拆开来。
它支持链式调用,Builder对象调用函数后会返回一个Builder对象本身,然后可以继续调用继续返回本身Builder对象。
类似于AlertDialog.Builder、GSonBuilder、EventBusBuildler、OkHttp网络请求框架的Request.Builder。
就拿AlertDialog来说:
这样的好处在哪?
这么说吧,先看看没有用Builder情况下的问题:
创建一个Person类,里面有这些属性:name,age,weight,height,分别给这些属性设置setter/getter方法和各种构造方法(无参、带两个参数、三个参数、四个参数….),然后我们可以通过创建Person实例的方式给Person赋值:
然后你就会发现,代码可读性很差,后面几个参数是什么鬼?自然,如果用了Builder模式来设计Person,就不会是这种结果了,我们来看看:
··· ···
然后我们就可以这样创建Person类:
这样的效果就是:代码可读性大大提高,一目了然!用一句话讲:Builder实现了构建与表示的分离!
2、使用场景
例如上面提到的AlertDialog,另外在okhttp/Glide上也有着Builder设计模式的身影。它的应用场景啊,其实就是当一个对象需要很多参数的时候,而且参数的个数或者类型不固定的时候。
3、UML结构图(基于经典Builder模式)
- Builder:它为创建一个产品Product对象的各个部件指定抽象接口
- ConcreteBuilder:它实现了Builder接口,实现各个部件的具体构造和装配方法
- Product:它是被构建的复杂对象,包含多个组成部分
- Director:指挥者又称为导演类,它负责安排复杂对象的建造次序,指挥者与抽象建造者之间存在关联关系
4、实例分析
在建造者模式的定义中提到了复杂对象,那么什么是复杂对象?简单来说,复杂对象是指那些包含多个成员属性的对象,这些成员属性也称为部件或零件,如汽车包括方向盘、发动机、轮胎等部件,电子邮件包括发件人、收件人、主题、内容、附件等部件,一个典型的复杂对象类代码示例如下:
class Product {
//定义类型,部件可以是任意类型,包括值类型和引用类型
private String partA;
private String partB;
private String partC;
//partA的Getter方法和Setter方法省略
//partB的Getter方法和Setter方法省略
//partC的Getter方法和Setter方法省略
}
在抽象建造者类中定义了产品的创建方法和返回方法,其典型代码如下:
abstract class Builder {
//创建产品对象
protected Product product = new Product();
//创建三个抽象的构建产品的方法
public abstract void buildPartA();
public abstract void buildPartB();
public abstract void buildPartC();
//返回产品对象
public Product getResult(){
return product;
}
}
在ConcreteBuilder中实现了buildPartX()方法,通过调用Product的setPartX()方法可以给产品对象的成员属性设值。
public class ConcreateBuilder extends Builder {
@Override
public void buildPartA() {
// 给对象设置属性的一些操作
}
@Override
public void buildPartB() {
}
@Override
public void buildPartC() {
}
}
在建造者模式的结构中还引入了一个指挥者类Director,该类主要有两个作用:一方面它隔离了客户与创建过程;另一方面它控制产品的创建过程,包括某个buildPartX()方法是否被调用以及多个buildPartX()方法调用的先后次序等。指挥者针对抽象建造者编程,客户端只需要知道具体建造者的类型,即可通过指挥者类调用建造者的相关方法,返回一个完整的产品对象。在实际生活中也存在类似指挥者一样的角色,如一个客户去购买电脑,电脑销售人员相当于指挥者,只要客户确定电脑的类型,电脑销售人员可以通知电脑组装人员给客户组装一台电脑。
//隔离和控制复杂对象的创建过程
public class Director {
private Builder builder;
public Director(Builder builder) {
super();
this.builder = builder;
}
public void setBuilder(Builder builder) {
this.builder = builder;
}
//产品构建和组装方法
public Product construct(){
builder.buildPartA();
builder.buildPartB();
builder.buildPartC();
return builder.getResult();
}
}
在指挥者类中可以注入一个抽象建造者类型的对象,其核心在于提供了一个建造方法construct(),在该方法中调用了builder对象的构造部件的方法,最后返回一个产品对象。
最后客户端代码片段如下:
public class BuilderClient {
public static void main(String[] args) {
Builder builder = new ConcreateBuilder();
Director director = new Director(builder);
Product product = director.construct();
}
}
5、builder模式的优点
- 松散耦合:建造者模式可以用一个构建算法构建出表现上完全不同的产品,实现构建和产品表现上的分离。唔,客户端不必知道产品内部组成的细节~
- 可以很容易的改变产品的内部表示
- 更好的复用性:生成器模式很好的实现构建算法和具体产品实现的分离
6、缺点
- 会产生多余的Builder对象以及Director对象,消耗内存
- 对象的构建过程会暴露