Builder建造者
建造者模式能解决复杂的产品生产过程,并且同工厂一样,能将生产内部逻辑与用户之间解耦。当然若要解决用户与建造者之间的耦合问题,则应该使用抽象建造者,与抽象工厂类似。
使用场景
使用建造者模式,意味着你生成的产品比较复杂,它不仅拥有很多参数需要配置,并且有很多可选项。当使用传统的构建函数或者工厂模式时,我们需要用很长的构造函数来指定必须的参数,并且,对于可选的参数,每增加一个参数,便需要增加一个构造函数。(对于可选参数这点,仅局限与Java这种构造函数不支持默认值的语言)
同样当你的产品的生成过程非常复杂,存在很多种可能性,需要用户来规定初始化步骤,但又不想将初始化的具体暴露给用户时,建造者模式也是不错的选择。
实现
假象一个场景,公司生成一种方形的盒子,盒子有长宽高,价格,编号,图案(集合)这些属性,其中编号是必须的,而别的是可选的,如果用户没有指定就是默认值。那么如果我们使用工厂模式,对应这四种可变参数,将会产生4 + 6 + 4 + 1 = 15种构造函数,这肯定不是我们想要的,因此我们采用Builder进行实现。
public class Product {
private int pId,width,height,length;
private List<Integer> patterns;
private long cost;
privateProduct(int pId, int width, int height, int length, List<Integer> patterns, long cost) {
this.pId = pId;
this.width = width;
this.height = height;
this.length = length;
this.patterns = patterns;
this.cost = cost;
}
static class ProductBuilder{
private int pId,width,height,length;
private List<Integer> patterns;
private long cost;
public ProductBuilder(int pId) {
this.pId = pId;
patterns = new LinkedList<>();
//default value
width = 500;
height = 500;
length = 500;
cost = 1000;
}
public ProductBuilder setCost(long cost){
this.cost = cost;
return this;
}
public ProductBuilder setWidth(int width){
this.width = width;
return this;
}
public ProductBuilder setHeight(int height){
this.height = height;
return this;
}
public ProductBuilder setLength(int length){
this.length = length;
return this;
}
public ProductBuilder appendPattern(int patternId){
this.patterns.add(patternId);
return this;
}
public Product build(){
return new Product(pId,width,height,length,patterns,cost);
}
}
}
可以从上面的实现看出,builder模式有效的减少了代码的数量,并且增加了灵活性和可读性。对于Product中的patterns这个List,使用Builder后用户甚至不需要自己初始化List,也不用关心Builder中的List是如何实现的,这一点使得Builder让内部逻辑对用户不可见。
在实现ProductBuilder时用到了几个小技巧,首先用private修饰Product的构造函数,使得用户只能通过Builder来构造Product,使得产品的发布更加安全。同时由于构造函数为private,因此Builder必须是Product的静态内部类。最后对于Builder中的每一个函数,都采用了函数式编程的思想,将返回值设为ProductBuilder本身,因为Builder的创建过程本身就是一套固定的流程,很少有需要判断(分支)的地方,因此用函数式可读性更高。(当然并不是所有的builder都是固定的流程,因此不是所有builder都适合函数式,这个取决于具体情况。)
例子
Builder模式很常见,列如JDK中的StringBuilder,各种框架的初始化,如Netty的ServerBootstrap,Spring的SpringApplicationBuilder。
优点
- 解决复杂的产品生产流程,减少代码量,解决Java中多可配置参数导致的构造函数数量爆炸的问题
- 用户能自由的选择产品的生产流程,然而产品生产的逻辑却对用户不可见。
- 可读性强,写着爽
- 延迟初始化,惰性.
缺点
- 没什么缺点
网友评论