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

常用设计模式有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;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")){
//如果是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>
 

 
我们写程序重构的最终目的就是:简单、清晰。代码是让人看的,不是 写完就完事了,
现在的高级语言,要像写中文 汉字一样,你写的,别人能看懂。
 
 
注意事项  
 
建造者模式关注的是零件类型和装配工艺(顺序),这是它与工厂方法模式最大不同的地方,虽然同为创建类模式,但是注重点不同。  
 
建造者模式最主要的功能是基本方法的调用顺序安排,也就是这些基本方法已经实现了,通俗地说就是零件的装配,顺序不同产生的对象也不同;而工厂方法则重点是创建,创建零件是它的主要职责,组装顺序则不是它关心的。 
 
 
 
建造者模式中还有一个角色没有说明,就是零件,建造者怎么去建造一个对象?是零件的组装,组装顺序不同对象效能也不同,这才是建造者模式要表达的核心意义,而怎么才能更好地达到这种效果呢?引入模板方法模式是一个非常简单而有效的办法。 
 
再次说明,在使用建造者模式的时候考虑一下模板方法模式,别孤立地思考一个模式,僵化地套用一个模式会让你受害无穷!  
 
 
 
 

8.Android中的源码分析

Android中的AlertDialog.Builder就是使用了Builder模式来构建AlertDialog的。

8.1 AlertDialog.Builder的简单用法

 

        AlertDialog.Builder builder = new AlertDialog.Builder(activity);//创建一个Builder对象
        builder.setIcon(R.drawable.icon);
        builder.setTitle("标题");
        builder.setMessage("信息");
        builder.setPositiveButton("确定",
                new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {

                    }
                });
        AlertDialog alertDialog = builder.create();//创建AlertDialog对象
        alertDialog.show();//展示AlertDialog

通过Builder对象来构建Icon、Title、Message等,将AlertDialog的构建过程和细节隐藏了起来。

8.2 AlertDialog相关源码分析

 

//AlertDialog源码
public class AlertDialog extends Dialog implements DialogInterface {
    private AlertController mAlert;//接受Builder成员变量P的参数

    AlertDialog(Context context, @StyleRes int themeResId, boolean createContextThemeWrapper) {
        super(context, createContextThemeWrapper ? resolveDialogTheme(context, themeResId) : 0, createContextThemeWrapper);
        mWindow.alwaysReadCloseOnTouchAttr();
        mAlert = AlertController.create(getContext(), this, getWindow());//创建AlertController对象
    }

    @Override
    public void setTitle(CharSequence title) {//设置Title
        super.setTitle(title);
        mAlert.setTitle(title);//保存在AlertController对象中
    }

    public void setMessage(CharSequence message) {//设置Message
        mAlert.setMessage(message);//保存在AlertController对象中
    }

    public void setIcon(@DrawableRes int resId) {//设置Icon
        mAlert.setIcon(resId);//保存在AlertController对象中
    }


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mAlert.installContent();//安装AlertDialog的内容
    }

    //AlertDialog其他代码略

    public static class Builder {
        private final AlertController.AlertParams P;//构建AlertDialog对象所需要的参数都存放在P中

        public Builder(Context context) {
            this(context, resolveDialogTheme(context, 0));
        }

        public Builder(Context context, int themeResId) {
            P = new AlertController.AlertParams(new ContextThemeWrapper(
                    context, resolveDialogTheme(context, themeResId)));//初始化AlertParams对象
        }

        public Context getContext() {
            return P.mContext;
        }

        public android.app.AlertDialog.Builder setTitle(CharSequence title) {
            P.mTitle = title;//保存title到P中
            return this;
        }

        public android.app.AlertDialog.Builder setMessage(CharSequence message) {
            P.mMessage = message;//保存message
            return this;
        }


        public android.app.AlertDialog.Builder setIcon(@DrawableRes int iconId) {
            P.mIconId = iconId;//保存IconId
            return this;
        }

        //Builder其他代码略

        public android.app.AlertDialog create() {//构建AlertDialog
            final android.app.AlertDialog dialog = new android.app.AlertDialog(P.mContext, 0, false);//创建一个AlertDialog对象
            P.apply(dialog.mAlert);//将P中的参数设置到AlertController中
            //其他设置代码略
            return dialog;
        }
    }
}

 

//Dialog源码
 public class Dialog implements DialogInterface, Window.Callback, KeyEvent.Callback, View.OnCreateContextMenuListener, Window.OnWindowDismissedCallback {
        //其他代码略
        public void show() {
            //前面代码略
            if (!mCreated) {
                dispatchOnCreate(null);//分发onCreate
            } else {
                final Configuration config = mContext.getResources().getConfiguration();
                mWindow.getDecorView().dispatchConfigurationChanged(config);
            }

            onStart();//调用onStart()
            mDecor = mWindow.getDecorView();
            
            //设置参布局参数略
           
            mWindowManager.addView(mDecor, l);//添加到WindowManager
            mShowing = true;

            sendShowMessage();
        }
        
        void dispatchOnCreate(Bundle savedInstanceState) {//分发onCreate
            if (!mCreated) {
                onCreate(savedInstanceState);//调用AlertDialog的onCreate方法,创建AlertDialog视图
                mCreated = true;
            }
        }
    }

 

//AlertController源码
public class AlertController {
        //其他代码略

        public void installContent() {//安装内容
            int contentView = selectContentView();//选择合适的布局
            mWindow.setContentView(contentView);//布局添加到Window中
            setupView();//把dialog.mAlert对象中需要构建的元素逐个添加设置到Window上,即构建我们设置的布局发生在这一步中
        }
    }

8.3 简单流程说明:

  1. 通过AlertDialog.Builder设置各种属性后(如:setTitle()),这些属性信息会保存在P变量中,P变量的类型为AlertController.AlertParams

  2. 调用builder.create()即可返回一个AlertDialog对象。
    2.1 builder.create()方法中首先会创建一个AlertDialog对象,AlertDialog对象构造时会初始化WindowManagerWindow
    2.2 builder.create()创建完AlertDialog对象后,会调用 P.apply(dialog.mAlert);即把P变量中所存储的用来构建AlertDialog对象的元素设置到了dialog.mAlert中,dialog.mAlert的类型为AlertController

  3. 调用AlertDialogshow()方法,展示界面。
    3.1 show()方法中会调用 dispatchOnCreate(null)dispatchOnCreate(null)调起onCreate(),onCreate()会调起mAlert.installContent();即安装AlertDialog的内容。
    3.2 installContent()中会调用mWindow.setContentView(mAlertDialogLayout);即把mAlertDialogLayout这个布局加到Window中去。
    3.3 调完mWindow.setContentView(mAlertDialogLayout)后会调用setupView()setupView()中会把dialog.mAlert对象中需要构建的元素逐个添加设置到mWindow上。
    3.4 最后通过把view添加到mWindowManager上展示出来。

8.4 总结:

  • builder模式隐藏了这种复杂的构建过程,只需几行简单的代码就把AlertDialog给展示出来了。
  • AlertDialogbuilder中并没有抽象建造者(Builder)、Director(指挥者类)等角色。AlertDialog.Builder同时扮演了BuilderConcreteBuilderDirector等角色,这是Android中的一种简化,也值得我们去学习使用。

 

 
 
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值