设计模式——Builder模式

Builder设计模式又叫做建造者模式

定义:

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

使用场景:

1、初始化一个对象时,有许多参数,并且好多都有默认值

2、一个类非常复杂,当调用类中的方法顺序不同时,结果也不同

如果有这些情况的时候,就可以考虑使用Builder模式来构建你的类了

Builder模式的UML图:

 

 

Director:代表统一组装的类

Builder:代表了抽象的Builder类,这里面规范产品的组成,一般由子类做具体的实现

ConcreteBuilder:代表了具体的Builder类

Product:具体的产品

我们先看看Android系统的源码中是如何使用Builder模式的。咱们以AlertDialog为例来讲解。

一般情况下我们都是这么使用AlertDialog的:

AlertDialog alertDialog = new AlertDialog.Builder(this)
                .setTitle("提示")
                .setMessage("我是一个弹框")
                .setPositiveButton("确定", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        Toast.makeText(MainActivity.this,"点击了确定",Toast.LENGTH_LONG).show();
                    }
                })
                .setNegativeButton("取消", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        Toast.makeText(MainActivity.this,"点击了取消",Toast.LENGTH_LONG).show();
                    }
                })
                .setCancelable(false)
                .create();
        alertDialog.show();

这段代码执行之后就会在在界面上弹出一个对话框

我们闲简单的画一个AlertDialog的UML图:

这里我只列出来了一些主要的参数和方法,

AlertDialog对应的就是我们的Product

Builder就是具体的ConcreteBuilder,这里面没有用到抽象的Builder

AlertParams代表Director

我们先看一下AlertDialog.Builder的源码:

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 Builder setTitle(CharSequence title) {
            P.mTitle = title;
            return this;
        }
        
           ...

        public Builder setMessage(CharSequence message) {
            P.mMessage = message;
           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;
        }

        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            mAlert.installContent();
        }

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

我这里做了一些删减,Builder中持有AlertParams的引用,用来保存dialog的一些参数,当我们调用create()的时候,会创建一个dialog,内部会去调用P的apply()方法。这个方法需要穿一个参数dialog.mAlert,这个参数来自AlertDialog,代码如下:

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

    AlertDialog(Context context, @StyleRes int themeResId, boolean createContextThemeWrapper) {
        super(context, createContextThemeWrapper ? resolveDialogTheme(context, themeResId) : 0,
                createContextThemeWrapper);

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

    ...

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mAlert.installContent();
    }

}

我们可以看到mAlert在构造方法中被初始化。再次回到P的apply方法中,在AlertParams的apply()方法中会一个一个的调用AlertController的setTitle()、setMessage()方法。

最后当我们调用Builder的show()方法的时候,内部会调用AlertDialog的生命周期方法onCreate()方法,在该方法的内部,调用了AlertController的installContent()方法,最终在屏幕上显示出Dialog。

现在让我们模仿AlertDialog的源码,写一个自己的builder模式。这个例子模拟的是组装一台电脑。

首先我们创建一个实体类Conputer,也就是Product。

public class Computer {

    //电脑名称
    private String mName;
    //cpu核心数
    private int mBoard;
    //显示器
    private String mDisplay;
    //操作系统
    private String mOs;

    Computer(){}

    void setName(String name){
        mName = name;
    }

    void setBoard(int board){
        mBoard = board;
    }

    void setDisplay(String display){
        mDisplay = display;
    }

    void setOs(String os){
        mOs = os;
    }

    @NonNull
    @Override
    public String toString() {
        return "电脑信息:\n型号:"+mName+"\nCPU数:"+mBoard+"\n显示屏:"+mDisplay+"\n操作系统:"+mOs;
    }
}

在这个类里面有一些参数和方法用来保存电脑的信息,我们重写了toString方法用来打印电脑的信息。

接着我们需要创建一个Params类,这个类就是ConcreteBuilder类。

class ComputerParams {

    //电脑名称
    private String mName;
    //cpu核心数
    private int mBoard;
    //显示器
    private String mDisplay;
    //操作系统
    private String mOs;

    void setName(String name){
        mName = name;
    }

    void setBoard(int board){
        mBoard = board;
    }

    void setDisplay(String display){
        mDisplay = display;
    }

    void setOs(String os){
        mOs = os;
    }

    void apply(Computer computer){
        if (mName!=null){
            computer.setName(mName);
        }
        if(mBoard>0){
            computer.setBoard(mBoard);
        }
        if (mDisplay!=null){
            computer.setDisplay(mDisplay);
        }
        if (mOs!=null){
            computer.setOs(mOs);
        }
    }
}

最后我们创建一个Builder类。

public class ComputerBuilder {

    private ComputerParams mParams;

    public ComputerBuilder(){
        if (mParams==null){
            mParams = new ComputerParams();
        }
    }

    public ComputerBuilder setName(String name){
        mParams.setName(name);
        return this;
    }

    public ComputerBuilder setBoard(int board){
        mParams.setBoard(board);
        return this;
    }

    public ComputerBuilder setDisplay(String display){
        mParams.setDisplay(display);
        return this;
    }

    public ComputerBuilder setOs(String os){
        mParams.setOs(os);
        return this;
    }

    public Computer builder(){
        Computer computer = new Computer();
        mParams.apply(computer);
        return computer;
    }
}

这里我简单的说明一下,AlertDialog的源码中把Product和Builder写在了一个文件中。Builder是Product的一个内部类。这里我们为了看的明显一点,将它们拆开成了两个文件。

我将Computer和ComputerParams的方法对外进行了隐藏处理。这样一来,别人使用的时候,就只能通过ComputerBuilder这个类进行Computer的创建。

在ComputerBuilder的类中又一个builder方法,在这个方法的内部会实例化一个Computer的对象,然后嗲用ComputerParams的apply方法对Conputer进行参数赋值。最后将构建好的computer返回。这样我们就模拟AlertDialog的Builder模式创建出来了一台电脑。下面是它的使用方式:

public static void main(String[] args) {
        Test test = new Test();
        test.createComputer();
    }

    private void createComputer(){
        Computer computer = new ComputerBuilder()
                .setName("MacBook Pro 2019")
                .setBoard(8)
                .setDisplay("内建视网膜LCD")
                .setOs("Mac os 10.15")
                .builder();
        System.out.println(computer.toString());

    }

在控制台上会打印出这台电脑的信息:

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值