在上一篇中简单的说了下模板方法模式,这篇将简单的介绍下建造者模式,基于前面的http://blog.csdn.net/j903829182/article/details/76576712
模式的一个改造。比如汽车启动的顺序需要可以控制设置,上篇的模式就不能够满足要求了,这里使用建造者模式来解决可以手动控制启动顺序的需求。类图如下:
编写一个汽车模型的抽象类,代码如下:
package com.jack.buildermodel;
import java.util.ArrayList;
/**
* Created by jack on 2017/8/3.
* 建造者模式
*/
public abstract class CarModel {
//这个参数是各个基本方法执行的顺序
private ArrayList<String> sequence = new ArrayList<>();
/**
* 模型启动准备开始跑了
*/
abstract void start();
/**
* 能发动还要能停下来
*/
abstract void stop();
/**
* 喇叭会响,可以出什么声音根据车子来决定
*/
abstract void alarm();
/**
* 引擎会响
*/
abstract void engineBoom();
/**
* 车子会跑
*/
public void run(){
for (int i= 0;i< this.sequence.size();i++) {
String actionName = this.sequence.get(i);
if ("start".equals(actionName)){
this.start();//启动汽车
}else if ("stop".equals(actionName)){
this.stop();//停止汽车
}else if ("alarm".equals(actionName)){
this.alarm();//喇叭开始响了
} else if ("enginboom".equals(actionName)) {
this.engineBoom();//引擎开始响了
}
}
}
//把传递过来的值传递到类内
public void setSequence(ArrayList<String> sequence) {
this.sequence = sequence;
}
}
使用上面的汽车模型,生产出宝马模型,代码如下:
package com.jack.buildermodel;
/**
* Created by jack on 2017/8/3.
* 宝马模型
*/
public class BMWModel extends CarModel {
@Override
void start() {
System.out.println("宝马跑起来");
}
@Override
void stop() {
System.out.println("宝马停车");
}
@Override
void alarm() {
System.out.println("宝马按喇叭");
}
@Override
void engineBoom() {
System.out.println("宝马引擎响起来");
}
}
再使用汽车模型,生产出奔驰模型,代码模型如下:
package com.jack.buildermodel;
/**
* Created by jack on 2017/8/3.
* 奔驰模型
*/
public class BenzModel extends CarModel {
@Override
void start() {
System.out.println("奔驰跑起来");
}
@Override
void stop() {
System.out.println("奔驰停车");
}
@Override
void alarm() {
System.out.println("奔驰按喇叭");
}
@Override
void engineBoom() {
System.out.println("奔驰引擎响起来");
}
}
到这里,宝马奔驰的模型都有了,下面我们来开始生产汽车,指定顺序让汽车跑起来吧!代码如下:
package com.jack.buildermodel;
import java.util.ArrayList;
/**
* Created by jack on 2017/8/3.
*/
public class MainTest1 {
public static void main(String[] args) {
CarModel carModel = new BenzModel();
//存放汽车的顺序动作
ArrayList<String> sequence = new ArrayList();
sequence.add("enginboom");
sequence.add("start");
sequence.add("stop");
sequence.add("enginboom");
//把动作赋予奔驰
carModel.setSequence(sequence);
carModel.run();
}
}
运行上面的代码,输出如下:
奔驰引擎响起来
奔驰跑起来
奔驰停车
奔驰引擎响起来
现在又有这样的需要,我需要一个宝马模型只要启动,停止,其他什么也不要,一个只要喇叭,然后启动,然后停止,第四个。。。。我们不可能为每个场景写一个类来满足,者时候我们给产品模型定义一个建造者,你要啥顺序直接告诉建造者,由建造者来建造,者就是建造者模型,类图如下:
抽象汽车建造者:
package com.jack.buildermodel;
import java.util.ArrayList;
/**
* Created by jack on 2017/8/3.
* 抽象类,建造者
*/
public abstract class CarBuilder {
//建造一个模型,你需要给我一个顺序要求,就是车的动作
public abstract void setSequence(ArrayList<String> sequence);
//设置完毕顺序后,就可以直接拿到这个模型了
public abstract CarModel getCarModel();
}
宝马建造者:
package com.jack.buildermodel;
import java.util.ArrayList;
/**
* Created by jack on 2017/8/3.
* 宝马建造者
*/
public class BMWBuilder extends CarBuilder{
private BMWModel bmwModel = new BMWModel();
@Override
public void setSequence(ArrayList<String> sequence) {
this.bmwModel.setSequence(sequence);
}
@Override
public CarModel getCarModel() {
return this.bmwModel;
}
}
奔驰建造者:
package com.jack.buildermodel;
import java.util.ArrayList;
/**
* Created by jack on 2017/8/3.
* 奔驰建造者
*/
public class BenzBuilder extends CarBuilder{
private BenzModel benzModel = new BenzModel();
@Override
public void setSequence(ArrayList<String> sequence) {
this.benzModel.setSequence(sequence);
}
@Override
public CarModel getCarModel() {
return benzModel;
}
}
测试代码如下:
package com.jack.buildermodel;
import java.util.ArrayList;
/**
* Created by jack on 2017/8/3.
*/
public class MainTest2 {
public static void main(String[] args) {
ArrayList<String> sequence = new ArrayList();
sequence.add("enginboom");
sequence.add("start");
sequence.add("stop");
sequence.add("enginboom");
//要一个奔驰
BenzBuilder benzBuilder = new BenzBuilder();
//设置顺序
benzBuilder.setSequence(sequence);
//制造一个奔驰出来
CarModel benz = benzBuilder.getCarModel();
benz.run();
System.out.println("--------------------");
//要一个通用顺序的宝马
BMWBuilder bmwBuilder = new BMWBuilder();
bmwBuilder.setSequence(sequence);
CarModel bmw = bmwBuilder.getCarModel();
bmw.run();
}
}
奔驰引擎响起来
奔驰跑起来
奔驰停车
奔驰引擎响起来
--------------------
宝马引擎响起来
宝马跑起来
宝马停车
宝马引擎响起来
上面是测试程序的输出。
需求总是再变,我们不知道需要具体什么方式的启动顺序,那么我们可以把封装一个模型,把各个事件的先后顺序都指定一个代码,你说一种立刻就可以给出处理的方法,类图如下:
上面的类图增加了一个Director类,还是比较简单的,负责按照指定顺序生产汽车模型,代码如下:
package com.jack.buildermodel;
import java.util.ArrayList;
/**
* Created by jack on 2017/8/3.
*/
public class Director {
private ArrayList<String> sequence = new ArrayList<>();
//宝马建造者
private BMWBuilder bmwBuilder = new BMWBuilder();
//奔驰建造者
private BenzBuilder benzBuilder = new BenzBuilder();
/**
* A类型车的奔驰模型,先start然后stop,其他没有
* @return
*/
public CarModel getABenzModel(){
this.sequence.clear();
this.sequence.add("start");
this.sequence.add("stop");
//按顺序返回一个奔驰车
benzBuilder.setSequence(sequence);
return benzBuilder.getCarModel();
}
/**
* B类型车的奔驰模型,先发动引擎,然后start,stop,其他没有
* @return
*/
public CarModel getBBenzModel(){
this.sequence.clear();
this.sequence.add("enginboom");
this.sequence.add("start");
this.sequence.add("stop");
//按顺序返回一个奔驰车
this.benzBuilder.setSequence(sequence);
return this.benzBuilder.getCarModel();
}
/**
* C类型车的宝马模型,先按喇叭,然后start,stop,其他没有
* @return
*/
public CarModel getCBWMModel(){
this.sequence.clear();
this.sequence.add("alarm");
this.sequence.add("start");
this.sequence.add("stop");
//按顺序返回一个奔驰车
this.bmwBuilder.setSequence(sequence);
return this.bmwBuilder.getCarModel();
}
/**
* D类型车的宝马模型,就一个功能,就是跑
* @return
*/
public CarModel getDBWMModel(){
this.sequence.clear();
this.sequence.add("start");
//按顺序返回一个奔驰车
this.bmwBuilder.setSequence(sequence);
return this.bmwBuilder.getCarModel();
}
//还可以有很多车型
}
测试类代码如下:
package com.jack.buildermodel;
/**
* Created by jack on 2017/8/3.
*/
public class MainTest3 {
public static void main(String[] args) {
Director director = new Director();
//100辆A类型的车
for (int i= 0 ;i<100;i++){
director.getABenzModel();
}
//100辆B类型的车
for (int i= 0 ;i<100;i++){
director.getBBenzModel();
}
//100辆C类型的车
for (int i= 0 ;i<100;i++){
director.getCBWMModel();
}
}
}
通用建造者模型类图如下:
Product类:通常是实现了模板方法模式,如上面的BenzModel和BMWModel
Builder抽象构建者:规范产品的组建,一般是由子类实现
ConcreteBuilder具体构构建者:实现抽象类定义的所有方法,并返回一个组建好的对象。
Director导演类:负责安排已经有的模块的顺序,然后告诉Builder开始构建
建造者模式的优点:
封装性:使用建造者模式可以使客户端不必知道产品内部组成的细节
建造者独立,容易扩展
便于控制细节风险:由于具体的建造者是独立的,因此可以对建造过程逐步细化,而不对其他模块产生任何影响。
建造者模式的使用场景:
1,相同的方法,不同的执行顺序,产生不同的世界结果时,可以采用建造者模式
2,多个部件或零件,都可以装配到一个对象中,但是产生的运行结果又不相同时
3,产品类非常复杂,或者产品类中的调用顺序不同产生了不同的效能
4,再对象创建过程中使用到了系统中的一些其他对象,这些对象再产品对象的创建过程中不易得到时,也可以采用建造者模式封装该对象的创建过程。
建造者模式关注的时零件类型和装配工艺顺序。
代码在github里面,地址:https://github.com/wj903829182/springboot/tree/master/designpattern