案例:造车,在模板方法模式中使用的案例是造车,继续扩展这个案例来介绍建造者模式。这次要造宝马汽车和奔驰汽车,但是要求:汽车的启动、停止、鸣笛、引擎轰鸣这些方法都由自己控制。
先设计一个不用设计模式实现的方式。
类图:
代码:
import java.util.ArrayList;
public abstract class Car {
private ArrayList<String> sequence = new ArrayList<>();
protected abstract void start();
protected abstract void stop();
protected abstract void alarm();
protected abstract void engineBoom();
// 设置启动顺序
final public void setSequence(ArrayList<String> sequence) {
this.sequence = sequence;
}
// 按照启动顺序执行4个方法
final public void run() {
for (int i = 0; i < sequence.size(); i++) {
String actionName = sequence.get(i);
if (actionName.equalsIgnoreCase("start")) {
start();
} else if (actionName.equalsIgnoreCase("stop")) {
stop();
} else if (actionName.equalsIgnoreCase("alarm")) {
alarm();
} else if (actionName.equalsIgnoreCase("engineBoom")) {
engineBoom();
} else {
System.out.println("无法识别:" + actionName);
System.exit(-1);
}
}
}
}
public class Benz extends Car {
@Override
protected void start() {
System.out.println("Benz start...");
}
@Override
protected void stop() {
System.out.println("Benz stop...");
}
@Override
protected void alarm() {
System.out.println("Benz alarm...");
}
@Override
protected void engineBoom() {
System.out.println("Benz engine boom...");
}
}
public class BMW extends Car {
@Override
protected void start() {
System.out.println("BMW start...");
}
@Override
protected void stop() {
System.out.println("BMW stop...");
}
@Override
protected void alarm() {
System.out.println("BMW alarm...");
}
@Override
protected void engineBoom() {
System.out.println("BMW engine boom...");
}
}
public class Client {
public static void main(String[] args) {
Benz benz = new Benz();
ArrayList<String> sequence = new ArrayList<>();
sequence.add("engineBoom");
sequence.add("start");
sequence.add("stop");
benz.setSequence(sequence);
benz.run();
}
}
接下来看看使用建造者模式怎么做。
类图:
代码:
import java.util.ArrayList;
public abstract class CarBuilder {
public abstract void setSequence(ArrayList<String> sequence);
public abstract Car getCar();
}
public class BenzBuilder extends CarBuilder {
private Benz benz = new Benz();
@Override
public void setSequence(ArrayList<String> sequence) {
benz.setSequence(sequence);
}
@Override
public Car getCar() {
return benz;
}
}
public class BMWBuilder extends CarBuilder {
private BMW bmw = new BMW();
@Override
public void setSequence(ArrayList<String> sequence) {
bmw.setSequence(sequence);
}
@Override
public Car getCar() {
return bmw;
}
}
public class Client {
public static void main(String[] args) {
ArrayList<String> sequence = new ArrayList<>();
sequence.add("engineBoom");
sequence.add("start");
sequence.add("stop");
BenzBuilder benzBuilder = new BenzBuilder();
benzBuilder.setSequence(sequence);
Benz benz = (Benz) benzBuilder.getCar();
benz.run();
BMWBuilder bmwBuilder = new BMWBuilder();
bmwBuilder.setSequence(sequence);
BMW bmw = (BMW) bmwBuilder.getCar();
bmw.run();
}
}
继续优化设计,设计一个专门的类来设置start()、stop()、alarm()、engineBoom()这4个方法的顺序。
修改类图:
增加了Director类,对Car的4个方法的顺序进行封装:
- A型号Benz,run()的顺序:start()、stop()
- B型号Benz,run()的顺序:engineBoom()、start()、stop()
- A型号BMW,run()的顺序:alarm()、start()、stop()
- B型号BMW,run()的顺序:start()
- ......
代码:
import java.util.ArrayList;
public class Director {
private ArrayList<String> sequence = new ArrayList<>();
private BenzBuilder benzBuilder = new BenzBuilder();
private BMWBuilder bmwBuilder = new BMWBuilder();
public Benz getABenz() {
sequence.clear();
sequence.add("start");
sequence.add("stop");
benzBuilder.setSequence(sequence);
return (Benz) benzBuilder.getCar();
}
public Benz getBBenz() {
sequence.clear();
sequence.add("engineBoom");
sequence.add("start");
sequence.add("stop");
benzBuilder.setSequence(sequence);
return (Benz) benzBuilder.getCar();
}
public BMW getABMW() {
sequence.clear();
sequence.add("alarm");
sequence.add("start");
sequence.add("stop");
bmwBuilder.setSequence(sequence);
return (BMW) bmwBuilder.getCar();
}
public BMW getBBMW() {
sequence.clear();
sequence.add("start");
bmwBuilder.setSequence(sequence);
return (BMW) bmwBuilder.getCar();
}
}
public class Client {
public static void main(String[] args) {
Director director = new Director();
for (int i = 0; i < 10; i++) {
director.getABenz().run();
}
for (int i = 0; i < 10; i++) {
director.getBBenz().run();
}
for (int i = 0; i < 10; i++) {
director.getABMW().run();
}
}
}
这就是建造者模式,其中涉及到一些角色:
- Client:客户端,比如项目中的其他模块
- Car抽象类以及Benz、BMW两个子类:产品类(Product),实现了模板方法模式,其中定义模板方法和基本方法
- CarBuilder以及BenzBuilder和BMWBuilder两个子类:建造者(Builder)
- Director:导演类,负责安排已有模块的顺序,依赖Builder进行建造
建造者模式和工厂模式(包括工厂方法模式和抽象工厂模式)非常类似,但是侧重点不同:
- 建造者模式是在基本方法已经实现的基础上,关注基本方法的调用顺序安排
- 工厂模式注重的是高效创建对象
本文原书:《您的设计模式》 作者:CBF4LIFE