架构设计Android开发Android开发经验谈

【设计模式笔记】(二)- Builder模式

2018-03-15  本文已影响335人  MrTrying

1.简述

Builder模式也就是建造者模式,先说定义,将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

首先,将复杂对象的创建过程和部件的表示分离出来,其实就是把创建过程和自身的部件解耦,使得构建过程和部件都可以自由扩展,两者之间的耦合降到最低。然后,再是相同的构建过程可以创建不同的表示,相同的组合也可以通过不同的部件创建出不同的对象。

可能使用场景

这只是举几个比较合适的例子而已

2.实现

看到这里可能回觉得这个模式怎么和android平时使用的不太一样啊!Builder一般不是只有Product和Builder么?

关于这点,有度娘过一下Builder模式,基本介绍都是这种结构,相对标准,这个标准的意思就是帮助学习该设计模式,并不是指一种用法,毕竟设计模式还是需要灵活使用。而没有Director该环节的实现方式就是对Builder模式的一种简化。

这是一个手机配置简化的抽象类,设置CPU、OS以、内存大小以及运存大小

public abstract class Phone {
    protected String mCPU;
    protected String mOS;
    protected int mMemorySize;
    protected int mStorageSize;

    public abstract void setCPU();

    public abstract void setOS();

    public void setMemorySize(int memorySize) {
        this.mMemorySize = memorySize;
    }

    public void setStorageSize(int storageSize) {
        this.mStorageSize = storageSize;
    }

    @Override
    public String toString() {
        return "{ \n CPU : " + mCPU + "\n OS : " + mOS + 
            " \n MemorySize : " + mMemorySize + "GB" + 
            " \n StorageSize : " + mStorageSize + "GB \n}";
    }
}

具体的IPhoneX的类,由于CPU和系统是固定,而内存和运存运存可选。

public class IPhoneX extends Phone {

    public  IPhoneX(){}

    @Override
    public void setCPU() {
        mCPU = "A11";
    }

    @Override
    public void setOS() {
        mOS = "iOS 11";
    }
}

抽象的Builder类,作为主要隔离作用的类,Phone的API的每一个方法都有对应的build方法,并都返回自身来实现链式API。

public abstract class Builder {
    //设置CPU
    public abstract Builder buildCPU();
    //设置系统
    public abstract Builder buildOS();
    //设置运存大小
    public abstract Builder buildMemorySize(int memorySize);
    //设置储存大小
    public abstract Builder buildStorageSize(int storageSize);
    //创建一个Phone对象
    public abstract Phone create();
}

IPhoneXBuilder,具体的Builder

public class IPhoneXBuilder extends Builder {

    private IPhoneX mIPhoneX = new IPhoneX();

    @Override
    public Builder buildCPU() {
        mIPhoneX.setCPU();
        return this;
    }

    @Override
    public Builder buildOS() {
        mIPhoneX.setOS();
        return this;
    }

    @Override
    public Builder buildMemorySize(int memorySize) {
        mIPhoneX.setMemorySize(memorySize);
        return this;
    }

    @Override
    public Builder buildStorageSize(int storageSize) {
        mIPhoneX.setStorageSize(storageSize);
        return this;
    }

    @Override
    public Phone create() {
        return mIPhoneX;
    }
}

Director类,负责构造Phone

public class Director {

    Builder mBuilder = null;

    public Director(Builder builder){
        mBuilder = builder;
    }

    public void construct(int memorySize,int storageSize){
        mBuilder.buildCPU()
            .buildOS()
            .buildMemorySize(memorySize)
            .buildStorageSize(storageSize);
    }
}

下面是测试代码

//构建器
Builder builder = new IPhoneXBuilder();
//Director
Director director = new Director(builder);
//封装构建过程
director.construct(6,256);
//构建Phone,输出相关信息
Log.i(TAG, builder.create().toString());

通过具体的IPhoneXBuilder类构建IPhoneX对象,Director封装了构建Phone对象的过程,隐藏构建的细节。BuilderDirector两个部分起到了将对象的构建过程和对象的表示分离的作用。

之前也提到过,真是开发中Director类一般会省略,直接使用Builder,采用链式API进行组装,在使用Buidler模式的过程中更加有效。

3.Android源码中得Builder模式实现

首先想到的就是AlertDialog.Builder,AlertDialog.Builder其实是AlertDialog的静态内部类,所有的dialog属性都暂存在AlertController.AlertParams的一个final对象中,以此来做到一个Builder对象只组装一次,却能构建出多个属性相同的dialog。

这里截取了AlertDialog中比较关键的代码,

public class AlertDialog extends AppCompatDialog implements DialogInterface {

    final AlertController mAlert;

    protected AlertDialog(@NonNull Context context, @StyleRes int themeResId) {
        super(context, resolveDialogTheme(context, themeResId));
        //构造AlertController对象
        mAlert = new AlertController(getContext(), this, getWindow());
    }
    
    //此处省略不知道多少代码。。。
    
    @Override
    public void setTitle(CharSequence title) {
        super.setTitle(title);
        mAlert.setTitle(title);
    }
    
    //******* 内部类Builder *******
    public static class Builder {
        //存储AlertDialog的相关属性
        private final AlertController.AlertParams P;
        private final int mTheme;
        
        public Builder(@NonNull Context context, @StyleRes int themeResId) {
            P = new AlertController.AlertParams(new ContextThemeWrapper(
                    context, resolveDialogTheme(context, themeResId)));
            mTheme = themeResId;
        }
        
        //...
        
        public Builder setTitle(@StringRes int titleId) {
            P.mTitle = P.mContext.getText(titleId);
            return this;
        }
        
        //...
        
        public AlertDialog create() {
            // We can't use Dialog's 3-arg constructor with the createThemeContextWrapper param,
            // so we always have to re-set the theme
            final AlertDialog dialog = new AlertDialog(P.mContext, mTheme);

            //将设置到Builder中得属性设置到dialog的mAlert中,再由mAlert设置到view上
            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;
        }
    }
}

还有一点值得关注,AlertDialog中的AlertController对象,是接收Builder成员变量AlertController.AlertParams中的各个参数。AlertControllerAlertController.AlertParams不太相同的地方是,AlertController中又真是的View和属性设置,而AlertController.AlertParams只是作为一个暂时存放属性值得对象,在apply()方法调用时将相关的属性值传递给AlertDialogAlertController对象,再由AlertController`对象设置到view上。

4.总结

Builder模式在Android开发中也是比较常用的,通常作为配置类的构建器,将配置的构建和表示分离,同时也是将配置从使用中隔离出来,避免过多的setter方法。在Builder模式的实现中经常通过链式调用实现,达到通俗易懂的目的。

优点:

缺点:

像网络框架(或图片加载框架)的Config的构建,也是Builder模式所适用的场景。总的来说,设计模式还是需要明白设计的主要目的,才能更好地使用各种模式去解决实际问题。

「推荐」设计模式系列

设计模式(零)- 面向对象的六大原则
设计模式(一)- 单例模式
设计模式(二)- Builder模式
设计模式(三)- 原型模式
设计模式(四)- 工厂模式
设计模式(五)- 策略模式
设计模式(六)- 状态模式
设计模式(七)- 责任链模式
设计模式(八)- 解释器模式
设计模式(九)- 命令模式
设计模式(十)- 观察者模式
设计模式(十一)- 备忘录模式
设计模式(十二)- 迭代器模式
设计模式(十三)- 模板方法模式
设计模式(十四)- 访问者模式
设计模式(十五)- 中介者模式
设计模式(十六)- 代理模式
设计模式(十七)- 组合模式
设计模式(十七)- 组合模式

本文内容基于《Android源码设计模式解析与实践》

上一篇下一篇

猜你喜欢

热点阅读