设计模式笔记--建造者模式

来源:互联网 发布:ps淘宝主图字体 编辑:程序博客网 时间:2024/05/17 22:31

常用设计模式有23中,分为:

创建型模式(主要用于创建对象)

1、单例模式    2、工厂方法模式    3、抽象工厂模式    4、建造者模式     5、原型模式 
行为型模式 (主要用于描述对象或类是怎样交互和怎样分配职责)

1、模板方法模式  2、中介者模式  3、命令模式    4、责任链模式   5、策略模式   6、迭代器模式  

7、观察者模式      8、备忘录模式   9、访问者模式   10、状态模式  11、解释器模式

结构型模式(主要用于处理类或对象的组合)

1、代理模式  2、装饰模式   3、适配器模式   4、组合模式   5、外观模式(门面模式)   6、享元模式   7、桥梁模式



建造者模式  

建造者模式(Builder Pattern)也叫做生成器模式,其定义如下: 

将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。 




在建造者模式中,有如下4个角色:

● Product产品类  
通常是实现了模板方法模式,也就是有模板方法和基本方法

● Builder抽象建造者  
规范产品的组建 

● ConcreteBuilder具体建造者  
实现抽象类定义的所有方法,并且返回一个组建好的对象  

● Director导演类  
负责安排已有模块的顺序,然后告诉Builder开始建造,  导演类起到封装的作用,避免高层模块深入到建造者内部的实现类。当然,在建造者模式比较庞大时,导演类可以有多个。

建造者模式的通用源代码

<span style="font-size:18px;">public class Product {public void doSomething(){//独立业务处理}}</span>


代码清单11-13 抽象建造者
<span style="font-size:18px;">public abstract class Builder {//设置产品的不同部分,以获得不同的产品public abstract void setPart();//建造产品public abstract Product buildProduct();}</span>
其中,setPart方法是零件的配置,什么是零件?其他的对象。
获得一个不同零件,或者不同的装配顺序就可能产生不同的产品。


具体的建造者 
<span style="font-size:18px;">public class ConcreteProduct extends Builder {private Product product = new Product();//设置产品零件public void setPart(){/** 产品类内的逻辑处理*/}//组建一个产品public Product buildProduct() {return product;}}</span>
需要注意的是,如果有多个产品类就有几个具体的建造者,而且这多个产品类具有相同接口或抽象类,


导演类
<span style="font-size:18px;">public class Director {private Builder builder = new ConcreteProduct();//构建不同的产品public Product getAProduct(){builder.setPart();/** 设置不同的零件,产生不同的产品*/return builder.buildProduct();}}  </span>
  

优点  

● 封装性  

● 建造者独立,容易扩展  

● 便于控制细节风险  


使用场景  

● 相同的方法,不同的执行顺序,产生不同的事件结果时,可以采用建造者模式。

● 多个部件或零件,都可以装配到一个对象中,但是产生的运行结果又不相同时,则可以使用该模式。

● 产品类非常复杂,或者产品类中的调用顺序不同产生了不同的效能,这个时候使用建造者模式非常合适。

● 在对象创建过程中会使用到系统中的一些其他对象,这些对象在产品对象的创建过程中不易得到时,也可以采用建造者模式封装该对象的创建过程。  



实例  制造悍马扩展 

新需求:汽车的启动、停止、喇叭声音、引擎声音都由客户自己控制,想什么顺序就什么顺序, 





CarModel源代码  
<span style="font-size:18px;">代码清单11-1 车辆模型的抽象类public abstract class CarModel {//这个参数是各个基本方法执行的顺序private ArrayList 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;iString 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")){//如果是engine boom关键this.engineBoom(); //引擎开始轰鸣}}}//把传递过来的值传递到类内final public void setSequence(ArrayList sequence){this.sequence = sequence;}}</span>


CarModel的设计原理是这样的,setSequence方法是允许客户自己设置一个顺序,是要先启动响一下喇叭再跑起来,还是要先响一下喇叭再启动。对于一个具体的模型永远都固定的,但是对N多个模型就是动态的了。在子类中实现父类的基本方法,run()方法读取sequence,然后遍历sequence中的字符串,哪个字符串在先,就先执行哪个方法。 

两个实现类分别实现父类的基本方法,奔驰模型如代码清单11-2所示。
<span style="font-size:18px;">代码清单11-2 奔驰模型代码public class BenzModel extends CarModel {protected void alarm() {System.out.println("奔驰车的喇叭声音是这个样子的...");}protected void engineBoom() {System.out.println("奔驰车的引擎是这个声音的...");}protected void start() {System.out.println("奔驰车跑起来是这个样子的...");}protected void stop() {System.out.println("奔驰车应该这样停车...");}}</span>
<span style="font-size:18px;">代码清单11-3 宝马模型代码public class BMWModel extends CarModel {protected void alarm() {System.out.println("宝马车的喇叭声音是这个样子的...");}protected void engineBoom() {System.out.println("宝马车的引擎是这个声音的...");}protected void start() {System.out.println("宝马车跑起来是这个样子的...");}protected void stop() {System.out.println("宝马车应该这样停车...");}} </span>
CarBuilder抽象类,由它来组装各个车模,要什么类型什么顺序的车辆模型,都由相关的子类完成。


<span style="font-size:18px;">代码清单11-5 抽象汽车组装者public abstract class CarBuilder {//建造一个模型,你要给我一个顺序要求,就是组装顺序public abstract void setSequence(ArrayList<String> sequence);//设置完毕顺序后,就可以直接拿到这个车辆模型public abstract CarModel getCarModel();}</span>

实现类
<span style="font-size:18px;">代码清单11-6 奔驰车组装者public class BenzBuilder extends CarBuilder {private BenzModel benz = new BenzModel();public CarModel getCarModel() {return this.benz;}public void setSequence(ArrayList sequence) {this.benz.setSequence(sequence);}}  </span>
<span style="font-size:18px;">代码清单11-7 宝马车组装者public class BMWBuilder extends CarBuilder {private BMWModel bmw = new BMWModel();public CarModel getCarModel() {return this.bmw;}public void setSequence(ArrayList<String> sequence) {this.bmw.setSequence(sequence);}}</span>


 Director类,导演类,负责按照指定的顺序生产模型
<span style="font-size:18px;">代码清单11-10 导演类public class Director {private ArrayList sequence = new ArrayList();private BenzBuilder benzBuilder = new BenzBuilder();private BMWBuilder bmwBuilder = new BMWBuilder();/** A类型的奔驰车模型,先start,然后stop,其他什么引擎、喇叭一概没有*/public BenzModel getABenzModel(){//清理场景,这里是一些初级程序员不注意的地方this.sequence.clear();//ABenzModel的执行顺序this.sequence.add("start");this.sequence.add("stop");//按照顺序返回一个奔驰车this.benzBuilder.setSequence(this.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(this.sequence);return (BenzModel)this.benzBuilder.getCarModel();}/** C型号的宝马车是先按下喇叭(炫耀嘛),然后启动,然后停止*/public BMWModel getCBMWModel(){this.sequence.clear();this.sequence.add("alarm");this.sequence.add("start");this.sequence.add("stop");this.bmwBuilder.setSequence(this.sequence);return (BMWModel)this.bmwBuilder.getCarModel();}/** D类型的宝马车只有一个功能,就是跑,启动起来就跑,永远不停止*/public BMWModel getDBMWModel(){this.sequence.clear();this.sequence.add("start");this.bmwBuilder.setSequence(this.sequence);return (BMWModel)this.benzBuilder.getCarModel();}/** 这里还可以有很多方法,你可以先停止,然后再启动,或者一直停着不动,静态的嘛* 导演类嘛,按照什么顺序是导演说了算*/}</span>

大家看一下程序中有很多this调用。这个我一般是这样要求项目组成员的,如果你要调用类中的成员变量或方法,需要在前面加上this关键字,不加也能正常地跑起来,但是不清晰,加上this关键字,我就是要调用本类中的成员变量或方法,而不是本方法中的一个变量。

还有super方法也是一样,是调用父类的成员变量或者方法,那就加上这个关键字,不要省略,这要靠约束,还有就是程序员的自觉性

注意 数据的clear的动作,以防止数据混乱。


场景类 
 
×公司要A类型的奔驰车1万辆,B类型的奔驰车100万辆,C类型的宝马车1000万辆,D类型的不需要,非常容易处理,如代码清单11-11所示。
<span style="font-size:18px;">代码清单11-11 导演类public class Client {public static void main(String[] args) {Director director = new Director();//1万辆A类型的奔驰车for(int i=0;i<10000;i++){director.getABenzModel().run();}//100万辆B类型的奔驰车for(int i=0;i<1000000;i++){director.getBBenzModel().run();}//1000万辆C类型的宝马车for(int i=0;i<10000000;i++){director.getCBMWModel().run();}}}</span>



我们写程序重构的最终目的就是:简单、清晰。代码是让人看的,不是写完就完事了,
现在的高级语言,要像写中文汉字一样,你写的,别人能看懂。


注意事项  

建造者模式关注的是零件类型和装配工艺(顺序),这是它与工厂方法模式最大不同的地方,虽然同为创建类模式,但是注重点不同。  

建造者模式最主要的功能是基本方法的调用顺序安排,也就是这些基本方法已经实现了,通俗地说就是零件的装配,顺序不同产生的对象也不同;而工厂方法则重点是创建,创建零件是它的主要职责,组装顺序则不是它关心的。 
 


建造者模式中还有一个角色没有说明,就是零件,建造者怎么去建造一个对象?是零件的组装,组装顺序不同对象效能也不同,这才是建造者模式要表达的核心意义,而怎么才能更好地达到这种效果呢?引入模板方法模式是一个非常简单而有效的办法。 
 
再次说明,在使用建造者模式的时候考虑一下模板方法模式,别孤立地思考一个模式,僵化地套用一个模式会让你受害无穷!  




0 0
原创粉丝点击