23种设计模式之--建造者模式
又是一个周三,快要下班了,老大突然拉住我,喜滋滋的告诉我:“XX公司很满意我们做的模型,又签订了一个合同,把奔驰、宝马的车辆模型都交给我们公司制作了,不过这次又额外增加了一个需求:汽车的启动、停止、喇叭声音、引擎声音都由客户自己控制,他想什么顺序就什么顺序, 这个没问题吧?”
又是一个时间紧,工程量大的项目。首先,我们分析一下需求,奔驰、宝马都是一个产品,它们有共有的属性,XX公司关心的是单个模型的运行过程:奔驰模型A先有引擎声音,然后再响喇叭;奔驰B是先启动起来,然后再有引擎声音,这才是XX公司要关心的。那到我们老大这边呢,就是满足人家的要求,要什么顺序就立马能产生什么顺序的模型出来,我就负责老大的要求实现出来,而且还要批量的,也就是说XX公司下单订购宝马A车模,我们老大马上就找我“生产一个这样的车模, 启动完毕后,喇叭响一下”,然后我们就准备开始批量生产这些模型。
看起来需求还是比较复杂,我们一个个解决,先从产品类入手。
public abstract class CarModel { private List<String> sequence = new ArrayList<String>(); final public void setSequence( List<String> sequence ) { this.sequence = sequence; } protected abstract void start(); protected abstract void stop(); protected abstract void alarm(); protected abstract void engineBoom(); final public void run() { for ( String actionName : sequence ) { 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(); } } } }
CarModel的设计原理是这样的,setSequence方法是允许客户自己设置一个顺序,是要先启动响一下喇叭再跑起来,还是要先响一下喇叭再启动。对于一个具体的模型永远都固定的,但是对于N多个模型就是动态的了。在子类中实现父类的基本方法,run方法读取sequence, 然后遍历sequence中的字符吕,哪个字符串在先,就先执行哪个方法。
奔驰模型代码:
public class BenzModel extends CarModel { @Override protected void alarm() { System.out.println( "Benz alarmming" ); } @Override protected void engineBoom() { System.out.println( "Benz startup engine boom" ); } @Override protected void start() { System.out.println( "Benz startting" ); } @Override protected void stop() { System.out.println( "Benz Stopping" ); } }
宝马模型代码:
public class BWMModel extends CarModel { @Override protected void alarm() { System.out.println( "BWM alarmming" ); } @Override protected void engineBoom() { System.out.println( "BWM startup engine boom" ); } @Override protected void start() { System.out.println( "BWM startting" ); } @Override protected void stop() { System.out.println( "BWM Stopping" ); } }
两个产品类实现都完成,我们来模拟一下XX公司的要求:生产一个奔驰模型,要求跑的时候,先发动引擎,然后再挂挡启动,然后停下来,不需要喇叭。
public class Client { public static void main( String[] args ) { CarModel benz = new BenzModel(); List<String> sequence = new ArrayList<String>(); sequence.add( "engine boom" ); sequence.add( "start" ); sequence.add( "stop" ); benz.setSequence( sequence ); benz.run(); } }
看, 我们组装了这样的一辆汽车,满足了XX公司的需求。但是想想我们的需求, 汽车动作顺序是要能够随意调整的。所有我们应该为产品模型定义一个建造者,你要啥顺序直接告诉建造者,由建造者建造。
这样才以批量生产某种类型的汽车。
public abstract class CarBuilder { public abstract void setSequence( List<String> sequence); public abstract CarModel getCarModel(); }
public class BenzBuilder extends CarBuilder { private CarModel benz = new BenzModel(); @Override public CarModel getCarModel() { return this.benz; } @Override public void setSequence( List<String> sequence ) { this.benz.setSequence( sequence ); } }
public class BWMBuilder extends CarBuilder { private CarModel bwm = new BWMModel(); @Override public CarModel getCarModel() { return this.bwm; } @Override public void setSequence( List<String> sequence ) { this.bwm.setSequence( sequence ); } }
现在我们生产同一种类型的汽车就容易多了
public class Client { public static void main( String[] args ) { List<String> sequence = new ArrayList<String>(); sequence.add( "engine boom" ); sequence.add( "start" ); sequence.add( "stop" ); BenzBuilder benzBuilder = new BenzBuilder(); benzBuilder.setSequence( sequence ); CarModel benz = benzBuilder.getCarModel(); benz.run(); } }
我们做项目时,经常会有一个共识:需求是无底洞,是无理性的,不可能你告诉它不增加需求就不增加,这4个过程(start,stop,alarm,engineBoom)按照排列组合有很多种,XX公司可以随意组合,它要什么顺序的车模我就必须生成什么顺序的车辆,客户就是上帝,所有我们应该找一个导演,指挥各个事件的先后顺序,然后为每种顺序指定一个代码,你说一种我们立刻给你生产处理。