模式的介绍

模式的定义

建造者模式(Builder Pattern)也叫生成器模式,定义如下:
Seperate the construction of a complex object from its represention so that the same construction process can create different representions.

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

模式的使用场景

  • 相同的方法,不同的执行顺序,产生不同的事件结果
  • 多个部件或零件,都可以装配到一个对象中,但是产生的运行结果又不相同
  • 产品类非常复杂,或者产品类中调用顺序不同产生不同的效果

UML类图

设计模式之建造者模式---Builder_设计模式

角色介绍

  • Product 产品类 :
    产品的抽象类,通常是实现了模板方法的模式
  • Builder 抽象建造者 :

抽象类, 规范产品的组建,一般是由子类实现具体的组件过程。

  • ConcreteBuilder 具体建造者:

具体的构建器,返回一个组建好的对象

  • Director :

统一组装过程(可省略)。

模式的简单实现

样例的简单介绍
在android中,AlertDialog的生成Builder是一个经典的建造者模式,我们可以采用建造者模式模拟AlertDialog的生成。

模拟实现:
AbstractAlertDialog类:抽象类,描述了对话框的title,message,icon, positiveButton ,neutralButton ,negativeButton ,show()方法模拟对话框弹出。

public abstract class AbstractAlertDialog {

    protected String title = "Title";
    protected String message = "Message";
    protected String icon = "Icon";
    protected String positiveButton = "PositiveButton";
    protected String neutralButton = "NeutralButton";
    protected String negativeButton = "NegativeButton";

    public abstract void setTitle(String title);
    public abstract void setMessage(String message);
    public abstract void setIcon(String icon);
    public abstract void setPositiveButton(String positiveButton);
    public abstract void setNeutralButton(String neutralButton);
    public abstract void setNegativeButton(String negativeButton);

    public void show(){
        System.out.println("AlertDialog: "+" title == " + title +",message == "+message
                +" ,icon==" + icon+ ",\n + PositiveButton == " + positiveButton
                +",neutralButton =="+neutralButton +",negativeButton == "+negativeButton);
    }
}

AlertDialog类:模拟对话框的具体类

public class AlertDialog extends AbstractAlertDialog{

    @Override
    public void setTitle(String title) {
        // TODO Auto-generated method stub
        super.title = title;
    }

    @Override
    public void setMessage(String message) {
        // TODO Auto-generated method stub
        super.message = message;
    }

    @Override
    public void setIcon(String icon) {
        // TODO Auto-generated method stub
        super.icon = icon;
    }

    @Override
    public void setPositiveButton(String positiveButton) {
        // TODO Auto-generated method stub
        super.positiveButton = positiveButton;
    }

    @Override
    public void setNeutralButton(String neutralButton) {
        // TODO Auto-generated method stub
        super.neutralButton = neutralButton;
    }

    @Override
    public void setNegativeButton(String negativeButton) {
        // TODO Auto-generated method stub
        super.negativeButton = negativeButton;
    }
}

AbstractBuilder :抽象建造类

public abstract class AbstractBuilder {

    public abstract void setTitle(String title);
    public abstract void setMessage(String message);
    public abstract void setIcon(String icon);
    public abstract void setPositiveButton(String positiveButton);
    public abstract void setNeutralButton(String neutralButton);
    public abstract void setNegativeButton(String negativeButton);

    public abstract AbstractAlertDialog create();
}

Builder :具体的建造类

public class Builder extends AbstractBuilder {

    private AbstractAlertDialog alertDialog = new AlertDialog();


    @Override
    public void setTitle(String title) {
        // TODO Auto-generated method stub
        alertDialog.setTitle(title);
    }

    @Override
    public void setMessage(String message) {
        // TODO Auto-generated method stub
        alertDialog.setMessage(message);
    }

    @Override
    public void setIcon(String icon) {
        // TODO Auto-generated method stub
        alertDialog.setIcon(icon);
    }

    @Override
    public void setPositiveButton(String positiveButton) {
        // TODO Auto-generated method stub
        alertDialog.setPositiveButton(positiveButton);
    }

    @Override
    public void setNeutralButton(String neutralButton) {
        // TODO Auto-generated method stub
        alertDialog.setNeutralButton(neutralButton);
    }

    @Override
    public void setNegativeButton(String negativeButton) {
        // TODO Auto-generated method stub
        alertDialog.setNegativeButton(negativeButton);
    }

    @Override
    public AbstractAlertDialog create() {
        // TODO Auto-generated method stub
        return alertDialog;
    }
}

Direct :导演类

public class Direct {

    private AbstractBuilder mbuilder = null;

    public Direct(AbstractBuilder builder){
        mbuilder = builder;
    }

    public AbstractBuilder constructor(String title,String message,String icon,
            String positiveButton,String neutralButton,String negativeButton){
        mbuilder.setTitle(title);
        mbuilder.setMessage(message);
        mbuilder.setIcon(icon);
        mbuilder.setPositiveButton(positiveButton);
        mbuilder.setNeutralButton(neutralButton);
        mbuilder.setNegativeButton(negativeButton);
        return mbuilder;
    }
}

MainFunction 类:

public class MainFunction {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        AbstractBuilder builder = new Builder();
        Direct direct = new Direct(builder);
        direct.constructor("myTitle", "myMessage", "myIcon", 
                "myPositiveButton", "myNeutralButton", "myNegativeButton").create().show();     
    }
}

程序输出:

AlertDialog:  title == myTitle,message == myMessage ,icon==myIcon,
 + PositiveButton == myPositiveButton,neutralButton ==myNeutralButton,negativeButton == myNegativeButton

从输出我们可以看到,我们生成了一个AlertDialog,其title,message,icon,PositiveButton,neutralButton,negativeButton为我们定义的值。

我们是不是觉得,这个AlertDialog和我们平时使用的方式不对啊,并且感觉这个方法还更复杂,并且不灵活。

对的,这是因为我完全对比建造者模式来模拟的,而android中对AlertDialog生成是简化了的建造者模式。我们修改一下代码,

public class MainFunction {

    public static void main(String[] args) {
        // TODO Auto-generated method stub

        AbstractBuilder builder = new Builder();
        builder.setIcon(" testIcon");
        builder.setMessage(" testMessage");
        builder.setNegativeButton("test_negativeButton");
        builder.setNeutralButton("test_neutralButton");
        builder.setPositiveButton("test_positiveButton");
        builder.setTitle("test_title");
        builder.create().show();

    }
}

看到没,现在的使用方法是不是和android中AlertDialog的使用方法一样了。对的,这也就是说android中的AlertDialog的建造生成者模式是没有使用Direct类,直接在Builder中组装生成。

程序输出:

AlertDialog:  title == test_title,message ==  testMessage ,icon== testIcon,
 + PositiveButton == test_positiveButton,neutralButton ==test_neutralButton,negativeButton == test_negativeButton

模式的优缺点

优点

  • 封装性

使用建造者模式可以不需要知道产品内部的组成细节

  • 建造者独立,容易扩展
  • 便于控制细节风险

由于具体的建造模式是独立的,因此可以对建造过程逐步细化,而不对其他的模块产生任何的影响

缺点

  • 会产生多余的Builder对象以及Director对象,消耗内存
  • 对象的构建过程暴露

Android源码中的模式实现

在Android源码中,我们最常用到的Builder模式就是AlertDialog.Builder, 使用该Builder来构建复杂的AlertDialog对象。

private void showDialog(Context context) {  
    AlertDialog.Builder builder = new AlertDialog.Builder(context);  
    builder.setIcon(R.drawable.ic_launcher);  
    builder.setTitle("Title");  
    builder.setMessage("Message");  
    builder.setPositiveButton("Button1",  
        new DialogInterface.OnClickListener() {  
            public void onClick(DialogInterface dialog, int whichButton) {  
                setTitle("点击了对话框上的Button1");  
            }  
    });  
    builder.setNeutralButton("Button2",  
        new DialogInterface.OnClickListener() {  
            public void onClick(DialogInterface dialog, int whichButton) {  
                setTitle("点击了对话框上的Button2");  
            }  
    });  
    builder.setNegativeButton("Button3",  
        new DialogInterface.OnClickListener() {  
            public void onClick(DialogInterface dialog, int whichButton) {  
                setTitle("点击了对话框上的Button3");  
            }  
    });  
    builder.create().show();
}

生成AlertDialog如图:

设计模式之建造者模式---Builder_建造者模式_02

现在,我们对应的查看AlertDialog的源码:

./frameworks/base/core/java/android/app/AlertDialog.java

关键代码:

public class AlertDialog extends Dialog implements DialogInterface {
    private AlertController mAlert;

    .........
    //构造函数
    protected AlertDialog(Context context) {
        this(context, resolveDialogTheme(context, 0), true);
    }
protected AlertDialog(Context context, int theme) {
        this(context, theme, true);
    }

    AlertDialog(Context context, int theme, boolean createThemeContextWrapper) {
        super(context, resolveDialogTheme(context, theme), createThemeContextWrapper);

        mWindow.alwaysReadCloseOnTouchAttr();
        mAlert = new AlertController(getContext(), this, getWindow());
    }

    protected AlertDialog(Context context, boolean cancelable, OnCancelListener cancelListener) {
        super(context, resolveDialogTheme(context, 0));
        mWindow.alwaysReadCloseOnTouchAttr();
        setCancelable(cancelable);
        setOnCancelListener(cancelListener);
        mAlert = new AlertController(context, this, getWindow());
    }

   //setter方法
    @Override
    public void setTitle(CharSequence title) {
        super.setTitle(title);
        mAlert.setTitle(title);
    }

    public void setCustomTitle(View customTitleView) {
        mAlert.setCustomTitle(customTitleView);
    }

    public void setMessage(CharSequence message) {
        mAlert.setMessage(message);
    }
    public void setView(View view) {
        mAlert.setView(view);
    }
    ....................

    //Builer
    public static class Builder {
        private final AlertController.AlertParams P;
        private int mTheme;
        //Builder构造函数
        public Builder(Context context) {
            this(context, resolveDialogTheme(context, 0));
        }

        public Builder(Context context, int theme) {
            P = new AlertController.AlertParams(new ContextThemeWrapper(
                    context, resolveDialogTheme(context, theme)));
            mTheme = theme;
        }

        public Context getContext() {
            return P.mContext;
        }
        //Builder中的setter方法
        public Builder setTitle(int titleId) {
            P.mTitle = P.mContext.getText(titleId);
            return this;
        }

        public Builder setTitle(CharSequence title) {
            P.mTitle = title;
            return this;
        }

        public Builder setCustomTitle(View customTitleView) {
            P.mCustomTitleView = customTitleView;
            return this;
        }

        public Builder setMessage(int messageId) {
            P.mMessage = P.mContext.getText(messageId);
            return this;
        }

        public Builder setMessage(CharSequence message) {
            P.mMessage = message;
            return this;
        }

        public Builder setIcon(int iconId) {
            P.mIconId = iconId;
            return this;
        }

        public Builder setIcon(Drawable icon) {
            P.mIcon = icon;
            return this;
        }
        ....................

        //create方法,返回一个AlertDialog对象
        public AlertDialog create() {
            final AlertDialog dialog = new AlertDialog(P.mContext, mTheme, false);
            P.apply(dialog.mAlert);
            dialog.setCancelable(P.mCancelable);
            if (P.mCancelable) {
                dialog.setCanceledOnTouchOutside(true);
            }
            dialog.setOnCancelListener(P.mOnCancelListener);
            dialog.setOnDismissListener(P.mOnDismissListener);
            if (P.mOnKeyListener != null) {
                dialog.setOnKeyListener(P.mOnKeyListener);
            }
            return dialog;
        }

        //show方法
        public AlertDialog show() {
            AlertDialog dialog = create();
            dialog.show();
            return dialog;
        }
    }

}

从源码来看,android中的AlertDialog的建造生成者模式是没有使用Direct类,直接在Builder中组装生成。Builder同时扮演了上文中提到的builder、ConcreteBuilder、Director的角色,简化了Builder模式的设计。

参考资料

(1).设计模式之禅—第11章 建造者模式
(2)Android设计模式源码解析之Builder模式
https://github.com/simple-android-framework/android_design_patterns_analysis/tree/master/builder/mr.simple