设计模式——构造者模式

430 阅读3分钟

一、概述

Builder模式直译过来就是构造者模式,它是用来构造复杂对象的一种创建型模式。用户不需要知道内部细节是如何构造的,这样可以更好的控制构造对象的流程。构造一个对象可能会很复杂,会有很多的构建参数,而builder模式就是将构造过程和构建参数分开,将构造过程隐藏,构建参数暴露出去,达到了解耦的目的。拿个组装电脑这个具体的例子说明,我们组装电脑的时候,我们知道需要组装cpu、内存条、主板、显卡等参数,而不用知道是怎么具体组装的,拿到店里店员给我们组装(自己装就不用杠了☻,或许这个例子并不是那么恰当)

二、使用

class CreateComputer{

    //主板
    var mBoard : String? = null
    //cpu
    var mCpu : String? = null
    //内存
    var mRam : String? = null
    //显卡
    var mGraphicsCard : String? = null

    private constructor(board : String?,cpu : String?,ram : String?,graphicsCard : String?){
        this.mBoard = board
        this.mCpu = cpu
        this.mRam = ram
        this.mGraphicsCard = graphicsCard
    }

    class Builder{
        private var board : String? = null
        private var cpu : String? = null
        private var ram : String? = null
        private var graphicsCard : String? = null

        fun setBoard(b:String?) : Builder{
            board = b
            return this
        }

        fun setCpu(c:String?) : Builder{
            cpu = c
            return this
        }

        fun setRam(r:String?) : Builder{
            ram = r
            return this
        }

        fun setGraphicsCard(g:String?) : Builder{
            graphicsCard = g
            return this
        }

        fun build() : CreateComputer{
            return CreateComputer(board,cpu,ram,graphicsCard)
        }
    }
}

还是举上面组装电脑的栗子,创建一个CreateComputer类。可以看到,使用private私有化了构造方法,外界无法直接创建CreateComputer的对象;在CreateComputer有一个嵌套类,里面暴露出了构造相关参数的方法;最后再通过一个build()方法,调用了CreateComputer的构造方法,这样就创建了CreateComputer的对象并返回,我们就可以得到这个返回对象得到相关的构造参数。

class BuilderModeActivity : Activity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_builder_mode)

        val myBuilder = CreateComputer.Builder()
        val myComputer = myBuilder.setBoard("华硕B365m")
                .setCpu("Intel i9-9900x")
                .setRam("金士顿海盗船16G")
                .setGraphicsCard("华硕GTX2080-super")
                .build()
        println("主板:${myComputer.mBoard}    CPU:${myComputer.mCpu}    内存:${myComputer.mRam}    显卡:${myComputer.mGraphicsCard}")
    }
}

在BuilderModeActivity类中对builder模式的使用,组装一台电脑。可以看到,先创建一个Builder对象,在这个对象中构造需要的组件参数,调用build()完成构造。这样就使用我们在使用builder模式的时候,无需知道内部细节是怎么构造的,主需要把相关组件参数传递进去就可以组装出一台电脑。

三、源码中的应用

在源码中builder模式的使用,我们能经常用到的就是AlertDialog,它的内部也是同样构造了一个Builder类,只是它把相关的构建参数封装在了AlertController.AlertParams对象中,最后通过create()方法构造出了一个AlertDialog对象。


...

public static class Builder {
    private final AlertController.AlertParams P;

    public Builder(Context context) {
        this(context, resolveDialogTheme(context, ResourceId.ID_NULL));
    }

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

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

    public Builder setTitle(@StringRes 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(@StringRes int messageId) {
        P.mMessage = P.mContext.getText(messageId);
        return this;
    }
    
    ...
    
    public AlertDialog create() {
        // Context has already been wrapped with the appropriate theme.
        final AlertDialog dialog = new AlertDialog(P.mContext, 0, 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;
    }

    public AlertDialog show() {
        final AlertDialog dialog = create();
        dialog.show();
        return dialog;
    }
}

下面是AlertController的部分构造参数:

public class AlertController {
...
    public static class AlertParams {
        public int mIconId = 0;
        public Drawable mIcon;
        public CharSequence mTitle;
        public View mCustomTitleView;
        public CharSequence mMessage;
        public CharSequence mPositiveButtonText;
        public DialogInterface.OnClickListener mPositiveButtonListener;
        ...
    }
...
}

四、总结

最后总结一下builder模式,使用private修饰构造方法,外界无法直接创建对象,只能通过内部Builder类的build方法;隐藏了构建对象的过程;暴露出给外部调用的方法,用于构造组件。

代码地址:github.com/leewell5717…

五、参考

Android Builder模式