因为我们公司制造的悍马汽车得到了客户的满意(Java设计模式之模板方法模式),所以宝马和奔驰也纷纷要和我们公司合作,但是客户提出了新的需求:汽车的启动、停止、喇叭声音、引擎声音都由客户自己控制,他想什么顺序就什么顺序,先看一下基本的类图:
代码如下:
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 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("engine boom")) {
engineBoom();
} else {
System.err.println("无法识别:" + actionName);
System.exit(-1);
}
}
}
// 允许用户自己设置设置一个启动顺序
final public void setSequence(ArrayList<String> sequence) {
this.sequence = sequence;
}
}
public class Benz extends Car {
@Override
protected void start() {
System.out.println("Benz's start()...");
}
@Override
protected void stop() {
System.out.println("Benz's stop()...");
}
@Override
protected void alarm() {
System.out.println("Benz's alarm()...");
}
@Override
protected void engineBoom() {
System.out.println("Benz's engineBoom()...");
}
}
public class BMW extends Car {
@Override
protected void start() {
System.out.println("BMW's start()...");
}
@Override
protected void stop() {
System.out.println("BMW's stop()...");
}
@Override
protected void alarm() {
System.out.println("BMW's alarm()...");
}
@Override
protected void engineBoom() {
System.out.println("BMW's engineBoom()...");
}
}
某客户要求,我先要1个奔驰车,要求跑的时候,先发动引擎,然后再挂档启动,然后停下来,不需要喇叭,代码这样实现:
public class Client {
public static void main(String[] args) {
Benz benz = new Benz();
ArrayList<String> sequence = new ArrayList<>();
sequence.add("engine boom");
sequence.add("start");
sequence.add("stop");
benz.setSequence(sequence);
benz.run();
}
}
运行结果:
Benz's engineBoom()...
Benz's start()...
Benz's stop()...
上面的方式可以实现自定义启动顺序的功能,但还不是建造者模式的风格,建造者模式的类图如下:
代码如下:
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("engine boom");
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();
}
}
运行结果:
Benz's engineBoom()...
Benz's start()...
Benz's stop()...
BMW's engineBoom()...
BMW's start()...
BMW's stop()...
这四个过程(start,stop,alarm,engineBoom)按照排列组合有很多种,那我们怎么满足这种需求呢?也就是要有个类来安排这几个方法组合,就像导演安排演员一样,那个先出场那个后出场,那个不出场,我们这个也叫导演类,那我们修改一下类图:
增加了Director类,这个类是做了层封装,类中的方法说明如下:
- A 型号的奔驰车辆模型是只有启动(start)、停止(stop)方法,其他的引擎声音、喇叭都没有;
- B 型号的奔驰车是先发动引擎(engine boom),然后启动(star),再然后停车(stop),没有喇叭;
- C 型号的宝马车是先喇叭叫一下(alarm),然后(start),再然后是停车(stop),引擎不轰鸣;
- D 型号的宝马车就一个启动(start),然后一路跑到黑,永动机,没有停止方法,没有喇叭,没有引擎轰鸣;
- E 型号、F 型号...等等,可以有很多,启动(start)、停止(stop)、喇叭(alarm)、引擎轰鸣(engineBoom)这四个方法在这个类中可以随意的自由组合,这里都可以实现,我们就以前4种举例说明。
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("engine boom");
sequence.add("start");
sequence.add("stop");
benzBuilder.setSequence(sequence);
return (Benz) benzBuilder.getCar();
}
public BMW getCBMW() {
sequence.clear();
sequence.add("alarm");
sequence.add("start");
sequence.add("stop");
bmwBuilder.setSequence(sequence);
return (BMW) bmwBuilder.getCar();
}
public BMW getDBMW() {
sequence.clear();
sequence.add("start");
bmwBuilder.setSequence(sequence);
return (BMW) bmwBuilder.getCar();
}
/*
* 这里还可以有很多方法,你可以先停止,然后再启动,或者一直停着不动,等等
* 导演类嘛,按照什么顺序是导演说了算
*/
}
然后Client就只与Director打交道了,客户说要A类型的奔驰车一万辆,B类型的奔驰车100万辆,C类型的宝马车1000万辆,D类型的不要:
public class Client {
public static void main(String[] args) {
Director director = new Director();
for (int i = 0; i < 10000; i++) {
director.getABenz().run();
}
for (int i = 0; i < 1000000; i++) {
director.getBBenz().run();
}
for (int i = 0; i < 10000000; i++) {
director.getCBMW().run();
}
}
}
这就是建造者模式,中间有几个角色需要说明一下:
- Client 就是客户,这个到具体的应用中就是其他的模块或者页面;
- CarModel 以及两个实现类 BenzModel 和 BMWModel 叫做产品类(Product Class),这个产品类实现了模板方法模式,也就是有模板方法和基本方法,这个参考上一节的模板方法模式;
- CarBuilder 以及两个实现类 BenzBuilder 和 BMWBuilder 叫做建造者(Builder Class);
- Director 类叫做导演类(Director Class),负责安排已有模块的顺序,然后告诉 Builder 开始建造。
大家看到这里估计就开始犯嘀咕了,这个建造者模式和工厂模式非常相似,是的,是非常相似,但是记住一点你就可以游刃有余的使用了:
建造者模式最主要功能是基本方法的调用顺序安排,也就是这些基本方法已经实现了;而工厂方法则重点是创建,你要什么对象我创造一个对象出来,组装顺序则不是他关心的。
本文原书:
《您的设计模式》 作者:CBF4LIFE
网友评论