导语
Builder模式是一步一步创建一个复杂对象的创建型模式(有的地方叫建造者模式),它允许用户在不知道内部构建细节的情况下,可以更精细地控制对象的构造流程。该模式是为了将构建复杂对象的过程和它的部件解耦,使得构建过程和部件的表示隔离开来。
主要内容
- Builder模式的定义
- Builder模式的使用场景
- Builder模式的UML类图
- Builder模式的实现方式
具体内容
Builder模式的定义
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
Builder模式的使用场景
- 相同的方法,不同的执行顺序,产生不同的事件结果时。
- 多个部件或零件,都可以装配到一个对象中,但是产生的运行结果又不相同时。
- 产品类非常复杂,或者产品类中的调用顺序不同产生了不同的效能,这个时候使用建造者模式非常合适。
- 当初始化一个对象特别复杂,如参数多,且很多参数都具有默认值时。
Builder模式的UML类图
Builder模式的UML类图如下所示。
角色介绍:
- Product 产品类 : 产品的抽象类。
- Builder : 抽象类, 规范产品的组建,一般是由子类实现具体的组件过程。
- ConcreteBuilder : 具体的构建器.
- Director : 统一组装过程(可省略)。
Builder模式的实现方式
电脑的组装过程较为复杂,步骤繁多,但是顺序却是不固定的。下面我们以组装电脑为例来演示一下简单且经典的builder模式。
计算机抽象类,即Products角色:
package com.dp.example.builder;
/**
* Computer产品抽象类, 为了例子简单, 只列出这几个属性
*/
public abstract class Computer {
protected String mBoard;
protected String mDisplay;
protected String mOs;
protected Computer() {
}
// 设置主板
public abstract void setBoard(String board){
this.mBoard = board;
}
// 设置显示器
public void setDisplay(String display){
this.mDisplay = display;
}
// 设置操作系统
public void setOs();
@Override
public String toString() {
return "Computer [mBoard = " + mBoard + ", mDisplay = " + mDisplay + ", mOs = " + mOs + "]";
}
}
具体的Computer类,Macbook
package com.dp.example.builder;
/**
* Mac电脑
*/
public class Macbook extends Computer {
protected Macbook() {
}
@Override
public void setOs() {
mOs = "Mac OS X 10.10";
}
}
抽象Builder类:
package com.dp.example.builder;
/**
* builder抽象类
*/
public abstract class Builder {
// 设置主板
public abstract void buildBoard(String board);
// 设置显示器
public abstract void buildDisplay(String display);
// 设置操作系统
public abstract void buildOs();
// 创建Computer
public abstract Computer create();
}
具体的Builder类,MacbookBuilder:
package com.dp.example.builder;
public class MacbookBuilder extends Builder {
private Computer mComputer = new Macbook();
@Override
public void buildBoard(String board) {
mComputer.setBoard(board);
}
@Override
public void buildDisplay(String display) {
mComputer.setDisplay(display);
}
@Override
public void buildOs() {
mComputer.setOs();
}
@Override
public Computer create() {
return mComputer;
}
}
Director类,负责构造Computer:
package com.dp.example.builder;
public class Director {
Builder mBuilder = null;
/**
* @param builder
*/
public Director(Builder builder) {
mBuilder = builder;
}
/**
* 构建对象
*
* @param board
* @param display
* @param os
*/
public void construct(String board, String display) {
mBuilder.buildCPU(board);
mBuilder.buildRAM(display);
mBuilder.buildOs();
}
}
测试代码:
/**
* 经典实现较为繁琐
*
* @author mrsimple
*
*/
public class Test {
public static void main(String[] args) {
// 构建器
Builder builder = new MacbookBuilder();
// Director
Director pcDirector = new Director(builder);
// 封装构建过程
pcDirector.construct("英特尔主板", "Retina显示器");
// 构建电脑,输出相关信息
System.out.println("Computer Info : " + builder.create().toString());
}
}
输出结果:
Computer Info : Computer [mBoard = 英特尔主板, mDisplay = Retina显示器, mOs = Mac OS X 10.10]
上述示例中,通过具体的MacbookBuilder来构建Macbook对象,而Directory封装了构建复杂产品对象的过程,对处隐藏构建细节。Builder与Director一起将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的对象。
值得注意的是,在现实开发过程中,Directory角色经常会被省略。而直接使用一个Builder来进行对象的组装,这个Builder通常为链式调用,它的关键点是每个setter方法都返回自身,也就是return this,这样就使得setter方法可以链式调用,代码大致如下:
new TestBuilder().setA("A").setB("B").create();
通过这种形式不仅去除了Director角色,整个结构也更加简单,也能对Product对象的组装过程有更精细的控制。
总结
Builder模式在Android开发中也较为常用,通常作为配置类的构建器将配置的构建和表示分离开来,同时也是将配置从目标类中隔离出来,避免过多的setter方法。Builder模式比较常见的实现形式是通过调用链实现,这样使得代码更简洁、易懂。
-
优点:
- 良好的封装性, 使用建造者模式可以使客户端不必知道产品内部组成的细节。
- 建造者独立,容易扩展。
- 在对象创建过程中会使用到系统中的一些其它对象,这些对象在产品对象的创建过程中不易得到。
-
缺点:
- 会产生多余的Builder对象以及Director对象,消耗内存。