建造者模式(Builder Pattern)
属于创建型模式
的一种,将多个简单对象构建成一个复杂的对象,构建过程抽象化,不同实现方法可以构造出不同表现(属性)的对象,还提供了一种更加优雅构建对象的方式…
<!– more –>
概述
有时候构建一个复杂的对象,需要经过好几步的处理,比如常用的StringBuffer、StringBuilder、以及Swagger(一种接口文档)
,都是以这种模式构建对象的
优点
-
建造者模式
比较独立,将对象本身与构建过程解耦 - 精准控制构建出的对象和内容,构造层和显示层是分离的
- 写法上更加优雅
缺点
- 范围受限,不适合差异较大的对象
- 内部复杂多变,构造类相对会多
适用场景
- 构建具有共同特性的复杂对象
相关模式
抽象工厂模式与建造者模式相似
,因为它也可以创建复杂对象。主要的区别是建造者模式
着重于一步步得构造出复杂对象。而抽象工厂模式
着重于多个系列的产品对象(简单的或是复杂的)。建造者
是在最后的一步返回对象,而对于抽象工厂来说,对象是立即返回的。
案例
传统方式
public class Summoner {
private String name;
private String type;
private String innate;
public Summoner(String name, String type, String innate) {
this.name = name;
this.type = type;
this.innate = innate;
}
}
简单的对象我们可以使用下面这种方式,因为属性较少这种方式还看的,但不幸的是如果要增加字段或我们还需要去扩展构造方法,且可读性
不好,相同类型的情况下在一定程度上混淆视听了
Summoner s1 = new Summoner("德玛","战士","战争雷霆");
为什么不调用无参数的构造函数,通过
setter
方法来减轻问题。
解答: 如果程序员忘记调用一个特定的setter
方法会发生什么?我们可能得到的是一个部分初始化的对象,而且编译器也不会检测出任何问题。
- 构造函数参数太多
- 错误的对象状态
使用模式
在我们的示例中,改造下召唤师类
public class Summoner {
private String name;
private String type;
private String innate;
private Summoner(Builder builder) {
this.name = builder.name;
this.type = builder.type;
this.innate = builder.innate;
}
protected static class Builder {
private String name;
private String type;
private String innate;
protected Builder name(String name) {
this.name = name;
return this;
}
protected Builder type(String type) {
this.type = type;
return this;
}
protected Builder innate(String innate) {
this.innate = innate;
return this;
}
protected Summoner build() {
return new Summoner(this);
}
}
}
public class BuilderDemo {
public static void main(String[] args) {
Summoner monkey = new Summoner.Builder().name("齐天大圣 - 孙悟空").type("上单 - AD").innate("基石天赋 - 战争雷霆").build();
System.out.println(monkey.toString());
Summoner mouse = new Summoner.Builder().name("瘟疫之源 - 图奇").type("下路 - ADC").innate("基石天赋 - 战阵热诚").build();
System.out.println(mouse.toString());
Summoner diann = new Summoner.Builder().name("皎月女神 - 戴安娜").type("中单 - AP").build();
System.out.println(diann.toString());
}
}
建造者模式
让我们写的代码更具可读性,可理解为建立复杂的物体。它往往是实现一个连贯的操作,从而更加直观,此处由于类型较为单一差距不大,但遇到复杂对象构建差距就立竿见影了
Summoner{name='齐天大圣 - 孙悟空', type='上单 - AD', innate='基石天赋 - 战争雷霆'}
Summoner{name='瘟疫之源 - 图奇', type='下路 - ADC', innate='基石天赋 - 战阵热诚'}
Summoner{name='皎月女神 - 戴安娜', type='中单 - AP', innate='null'}
总结
我们通过一个简单的代码例子开始,慢慢变得复杂。然后使用Builder模式
来解决我们发现的问题。
如果你发现自己在一个情况下,你不断添加新参数的构造函数,使得代码变得容易出错,很难读,也许可以考虑使用一个Builder
重构你的代码。
推荐
- lombok: https://github.com/rzwitserloot/lombok
- IntelliJ IDEA : InnerBuilder 插件
– 说点什么
全文代码:https://gitee.com/battcn/design-pattern/tree/master/Chapter4/battcn-builder
- 个人QQ:1837307557
- battcn开源群(适合新手):391619659
微信公众号:battcn
(欢迎调戏)