建造者模式
-- 什么是建造者模式?
-- 建造者模式应用场景?
-- 建造者模式和工厂模式的区别?
定义
指将一个复杂对象的构造与它的表示分离,使同样的构建过程可以创建不同的表示。
应用场景
建造者(Builder)模式创建的是复杂对象,其产品的各个部分经常面临着剧烈的变化,但将它们组合在一起的算法却相对稳定,所以它通常在以下场合使用。
- 创建的对象较复杂,由多个部件构成,各部件面临着复杂的变化,但构件间的建造顺序是稳定的。
- 创建复杂对象的算法独立于该对象的组成部分以及它们的装配方式,即产品的构建过程和最终的表示是独立的。
实现
展现的是《设计模式之禅》里面的例子。以车模型为例,每种车都可根据几个动作排布。
CarModel.java
public abstract class CarModel {
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 < this.sequence.size(); i++){
String actionName = this.sequence.get(i);
if (actionName.equalsIgnoreCase("start")) {
this.start();
} else if (actionName.equalsIgnoreCase("stop")) {
this.stop();
} else if (actionName.equalsIgnoreCase("alarm")) {
this.alarm();
} else if (actionName.equalsIgnoreCase("engine boom")) {
this.engineBoom();
}
}
}
final public void setSequence (ArrayList sequence) {
this.sequence = sequence;
}
}
BenzModel.java
public class BenzModel extends CarModel {
@Override
protected void alarm() {
System.out.println("奔驰车的喇叭声音是这个样子的...");
}
@Override
protected void engineBoom() {
System.out.println("奔驰车的引擎是这个声音的...");
}
@Override
protected void start() {
System.out.println("奔驰车跑起来是这个样子的...");
}
@Override
protected void stop() {
System.out.println("奔驰车应该这样停车...");
}
}
BMWModel.java
public class BMWModel extends CarModel {
@Override
protected void alarm() {
System.out.println("宝马车的喇叭声音是这个样子的...");
}
@Override
protected void engineBoom() {
System.out.println("宝马车的引擎是这个声音的...");
}
@Override
protected void start() {
System.out.println("宝马车跑起来是这个样子的...");
}
@Override
protected void stop() {
System.out.println("宝马车应该这样停车...");
}
}
Client.java
public class Client {
public static void main(String[] args) {
//传统做法
BenzModel benz = new BenzModel();
ArrayList<String> sequence = new ArrayList<>();
sequence.add("engine boom"); // 客户要求,run的时候先发动引擎
sequence.add("start"); // 启动起来
sequence.add("stop"); // 开了一段就停下来
// 我们把这个顺序赋予奔驰车
benz.setSequence(sequence);
benz.run();
}
}
传统的做法到这里就直接将动作顺序在调用端一一列出来了,但这样的话,如果再来一个别的动作顺序,又得再列一大串代码,直到把你逼疯。其次,如果其他地方也要用到这个车模型,就得再copy一遍。下面加入建造者看下~
CarBuilder.java
public abstract class CarBuilder {
public abstract void setSequence(ArrayList<String> sequence);
public abstract CarModel getCarModel();
}
BenzBuilder.java
public class BenzBuilder extends CarBuilder {
private BenzModel benz = new BenzModel();
@Override
public void setSequence(ArrayList<String> sequence) {
this.benz.setSequence(sequence);
}
@Override
public CarModel getCarModel() {
return benz;
}
}
BMWBuilder.java
public class BMWBuilder extends CarBuilder {
private BMWModel bmw = new BMWModel();
@Override
public void setSequence(ArrayList<String> sequence) {
this.bmw.setSequence(sequence);
}
@Override
public CarModel getCarModel() {
return bmw;
}
}
建造者创建完了,还需要一个指挥官来指挥建造者才行,指挥官想生成3种类型的奔驰。
Director.java
public class Director {
private ArrayList<String> sequence = new ArrayList<>();
private BenzBuilder benzBuilder = new BenzBuilder();
private BMWBuilder bmwBuilder = new BMWBuilder();
//A类型的奔驰
public BenzModel getABenzModel() {
//清理场景,这里是一些初级程序员不注意的地方
this.sequence.clear();
this.sequence.add("start");
this.sequence.add("stop");
this.benzBuilder.setSequence(sequence);
return (BenzModel) this.benzBuilder.getCarModel();
}
//B类型的奔驰
public BenzModel getBBenzModel() {
//清理场景,这里是一些初级程序员不注意的地方
this.sequence.clear();
this.sequence.add("engine boom");
this.sequence.add("start");
this.sequence.add("stop");
this.benzBuilder.setSequence(sequence);
return (BenzModel) this.benzBuilder.getCarModel();
}
//C类型的奔驰
public BenzModel getCBenzModel() {
//清理场景,这里是一些初级程序员不注意的地方
this.sequence.clear();
this.sequence.add("alarm");
this.sequence.add("start");
this.sequence.add("stop");
this.benzBuilder.setSequence(sequence);
return (BenzModel) this.benzBuilder.getCarModel();
}
}
Client.java
public class Client {
public static void main(String[] args) {
//传统做法
...
//建造者模式
System.out.println("==========A==========");
Director director = new Director();
director.getABenzModel().run();
System.out.println("==========B==========");
director.getBBenzModel().run();
System.out.println("==========C==========");
director.getCBenzModel().run();
}
}
最后,在客户想要那种车模型的时候,指挥官就马上去安排了。
建造者模式和工厂模式的区别?
学完这个模式的时候,一开始还是有点蒙圈的,将初始化的零散工作放在一个方法里,在调用的时候直接根据类型去获取,这不是工厂模式吗?但仔细回想上个例子,汽车是一个工厂,然后子部件如空调,发动机作为一个单独的对象,在工厂里面有创建方法,当需要哪个部件的时候,就通过工厂方法去实例化出来。 而建造者模式是将A,B,C类型的车作为一个整体,通过指挥官去组装。
从这两个例子也就可以看出: 建造者模式注重零部件的组装过程,而工厂方法模式更注重零部件的创建过程。
《设计模式之禅》 对于这两者的区别是这么理解的:
建造者模式最主要的功能是基本方法的调用顺序安排,也就是这些基本方法已经实现了,通俗地说就是零件的装配,顺序不同产生 的对象也不同;
而工厂方法则重点是创建,创建零件是它的主要职责,组装顺序则不是它关心的。