前言
Builder模式是一步步创建一个复杂对象的创建型模式,它允许用户在不知道内部构建细节的情况下,可以更加精准的控制对象的构造过程,为了在构建过程中,对外部隐藏实现细节,就可以使用Builder模式将部件和组装过程分离,使得构建过程和部件可以自由扩展,两者之间的耦合度也降到最低。
定义
将一个复杂对象的构建和它的表示分离,使得同样的构建过程可以创建不同的表示。
使用场景
(1)相同的方法不同的执行顺序产生不同的事件结果时
(2)多个部件或零件,都可以装配到一个对象中,但是产生的运行结果又不同时
(3)产品类比较复杂或者产品类中的调用顺序不同产生不同的作用时
(4)当初始化一个对象非常复杂,如参数非常多,且很多参数都具有默认值时
类图
类图介绍:
- Produc - 产品的抽象类
- Builder - 抽象的Builder类,规范产品的组建,一般由子类实现具体的组建过程
- ConcreteBuilder - 具体的Builder类
- Director - 统一组装过程
简单实现
计算机的组装过程比较复杂且组装顺序说不固定的,下面把计算机的组装过程简化为构建主机,设置操作系统,设置显示器3部分,然后通过Director和具体Builder来构建计算机对象。
计算机抽象类,即Product
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| public abstract class Computer {
protected String mBroad; protected String mDisplay; protected String mOS;
protected Computer(){}
public void setmBroad(String broad){ mBroad = broad; }
public void setmDisplay(String display){ mDisplay = display; }
public abstract void setmOS();
@Override public String toString() { return "Computer {mBroad = " + mBroad + ", mDisplay = " + mDisplay + ", mOS = " + mOS + "}"; } }
|
苹果电脑,具体的Product
1 2 3 4 5 6 7 8 9
| public class Macbook extends Computer {
protected Macbook() {}
@Override public void setmOS() { mOS = "Mac OS X 10.10"; } }
|
抽象Builder类
1 2 3 4 5 6 7 8
| public abstract class Builder {
public abstract void buildBroad(String broad); public abstract void buildDisplay(String display); public abstract void buildOS(); public abstract Computer create();
}
|
具体的Builder类,构造苹果电脑
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| public class MacBuilder extends Builder {
private Computer mComputer = new Macbook();
@Override public void buildBroad(String broad) { mComputer.setmBroad(broad); }
@Override public void buildDisplay(String display) { mComputer.setmDisplay(display); }
@Override public void buildOS() { mComputer.setmOS(); }
@Override public Computer create() { return mComputer; } }
|
Director类,负责构造Computer
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public class Director { private Builder mBuilder;
public Director(Builder builder) { this.mBuilder = builder; }
public void construct(String broad, String display){ mBuilder.buildBroad(broad); mBuilder.buildDisplay(display); mBuilder.buildOS(); } }
|
测试代码
1 2 3 4 5 6 7 8 9 10 11 12
| public class Test {
public static void main(String[] args){ Builder builder = new MacBuilder(); Director director = new Director(builder); director.construct("英特尔主板", "Retina 显示器"); System.out.println("Computer Info: " + builder.create().toString()); } }
输出结果 : Computer Info: Computer {mBroad = 英特尔主板, mDisplay = Retina 显示器, mOS = Mac OS X 10.10}
|
上面代码中,通过具体的MacBuilder来构建Macbook对象,而Director封装构建复杂对象的过程,对外隐藏细节。Builder与Director一起将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的对象。
但在现实开发中,Director常常被忽略,直接使用一个Builder对象来进行链式调用构造,它的关键点是每个setter返回自身,如下,我们来组装一个华硕电脑:
华硕电脑,具体的产品类
1 2 3 4 5 6 7
| public class ASUSbook extends Computer {
@Override public void setmOS() { mOS = "Windows 10 专业版"; } }
|
抽象Builder类
1 2 3 4 5 6 7 8
| public abstract class Builder2 {
public abstract Builder2 buildBroad(String broad); public abstract Builder2 buildDisplay(String display); public abstract Builder2 buildOS(); public abstract Computer create(); }
|
具体的Builder类,构造ASUS电脑
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| public class ASUSBuilder extends Builder2 {
private Computer mComputer = new ASUSbook();
@Override public Builder2 buildBroad(String broad) { mComputer.setmBroad(broad); return this; }
@Override public Builder2 buildDisplay(String display) { mComputer.setmDisplay(display); return this; }
@Override public Builder2 buildOS() { mComputer.setmOS(); return this; }
@Override public Computer create() { return mComputer; } }
|
测试代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public class Test {
public static void main(String[] args){ Builder2 builder2 = new ASUSBuilder(); ASUSbook asusbook = (ASUSbook) builder2 .buildBroad("AMDB350socketAM4") .buildDisplay("AOC 显示器") .buildOS() .create(); System.out.println("Computer Info: " + asusbook.toString());
} }
输出结果 : Computer Info: Computer {mBroad = AMDB350socketAM4, mDisplay = AOC 显示器, mOS = Windows 10 专业版}
|
链式调用形式不仅去除Director角色,让整个结构简单,而且也能对product对象的组装过程有更加精准的控制。
然而上面的只是经典的实现方式,下面才是现在开发中最常用的,通过把Builder与产品类封装在一起,建立于上面的基础。
联想电脑,把Builder与产品类封装在一起
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| public class LenovoBook extends Computer {
private LenovoBook(Builder builder){ setmOS(); setmBroad(builder.broad); setmDisplay(builder.display); }
@Override public void setmOS() { mOS = "Windows 10 家庭中文版"; }
public static class Builder extends Builder2{
String broad; String display;
@Override public Builder2 buildBroad(String broad) { this.broad = broad; return this; }
@Override public Builder2 buildDisplay(String display) { this.display = display; return this; }
@Override public Builder2 buildOS() { return this; }
@Override public Computer create() { return new LenovoBook(this); } } }
|
测试代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| public class Test {
public static void main(String[] args){
LenovoBook lenovoBook = (LenovoBook) new LenovoBook.Builder() .buildOS() .buildBroad("联想主板") .buildDisplay("联想显示器") .create();
System.out.println("Computer Info: " + lenovoBook.toString()); } }
输出结果: Computer Info: Computer {mBroad = 联想主板, mDisplay = 联想显示器, mOS = Windows 10 家庭中文版}
|
总结
Builder模式在开发中很常用,通过把产品类的构造器,字段私有化,只能通过Builder来设置属性,也通常作为配置类的构造器将配置的构建与表示分离开来,同时也是将配置从目标类中独立出来,避免过多的setter方法。Builder模式常用的实现形式是链式调用。
本文源码相关位置
最終更新:
谢谢大家的阅读!