设计模式app开发Android知识

建造者模式(Builder)及其应用

2016-08-04  本文已影响561人  程序员徐公

建造者模式(Builder)及其应用


转载请注明原博客地址:

其实建造者模式在我们平时写项目的时候我们经常看到,大部分人没仔细观察或者不熟悉建造者模式,才忽略了它,在我们常用的ImageLoader和Rxjava里面其实都运用了建造者模式

本篇博客主要讲解一下几个问题

  1. 什么是建造者模式
  2. 建造者模式的应用场景,小Demo及优缺点分析
  3. 建造者模式在Android源码中的体现
  4. 建造者模式在常见的开源框架中ImageLoader和Rxjava的体现

1)什么是建造者模式

概念

简单来说,就是一步步创建一个对象,它对用户屏蔽了里面构建的细节,但却可以精细地控制对象的构造过程。

类UML图

Builder:可以是一个接口或者一个抽象类,主要是统一标准,便于我们使用多态而已
ConcreteBuilder:Builder的实现类,主要负责组建Product。
导演类(Director):主要负责统一指挥构建组装Product,但是它是不知道Product里面具体是怎样做的。
Product:产品类,是我们需要建造的复杂对象,可以是抽象类也可以是具体类,视对象的复杂程度而定

2) 建造者模式的应用场景,小Demo及优缺点分析

假设我们现在是手机生产商,主要负责手机的组装,手机的品牌有挺多的,有索尼,三星,小米等品牌,同一个品牌的手机的分辨率,CPU,摄像头肯能一样也可能不一样,你会怎么做呢?

有人说用抽象工厂模式?
刚开始想这样也是挺好的?
对于不同的手机品牌,我们单独有一个工厂实现子类,接着再交给工厂子类自己去实现手机。

不过后面自己想了一下,工厂模式诞生的初衷只是负责生产对象,而不必要知道生产手机的细节,而题目中要求同一个品牌的手机的分辨率,CPU,摄像头,这不就要求我们需要生产手机的细节了吗?所以使用抽象工厂模式不是最好的选择

下面我们来看一下使用Builder模式设计的UML图

下面我们一起来看一下例子代码

抽象Product类

//抽象Product类
public abstract class Phone {

    protected String mCPU;
    protected String mCamera;
    protected String mScreen;
    
    protected String mSystem;
    
    public abstract void setSystem();
    
    public  void setmCPU(String cpu){
        this.mCPU=cpu;
    }
    
    public void setmCamera(String camera) {
        this.mCamera = camera;
    }

    public void setmScreen(String screen) {
        this.mScreen = screen;
    }
    

}

具体Product类

/**
 * ContreteProduct类
 * @author xujun
 *
 */
public class SonyPhone extends Phone {


    @Override
    public void setSystem() {
        mSystem="Android";
        
    }

    @Override
    public String toString() {
        return "SonyPhone [mCPU=" + mCPU + ", mCamera=" + mCamera
                + ", mScreen=" + mScreen + ", mSystem=" + mSystem + "]";
    }
    
}

抽象Builder类

/**
 * 抽象Builder类
 * @author xujun
 *
 */
public abstract class Builder {
     
    public abstract void builderScreen(String screen);
    public abstract void buildCamera(String camrea);
    public abstract void buildCpu(String cpu);
    /**
     * 获得我们建造的Product对象
     * @return
     */
    public abstract Phone creat();
    public abstract void buildSystem();

}

Builder类实现类

public class SonyBuilder extends Builder {
    
    SonyPhone sonyPhone;

    public SonyBuilder() {
        sonyPhone=new SonyPhone();
    }

    @Override
    public void builderScreen(String screen) {
        sonyPhone.setmScreen(screen);
        
    }

    @Override
    public void buildCamera(String camrea) {
        
        sonyPhone.setmCamera(camrea);
    }

    @Override
    public void buildCpu(String cpu) {
        sonyPhone.setmCPU(cpu);
        
    }

    @Override
    public Phone creat() {
        return sonyPhone;
    }

    @Override
    public void buildSystem() {
           sonyPhone.setSystem();
    }
    

}

Director类

public class Director {
    
    Builder mBuilder;
    String mScreen="1920x720";
    String mCPU="双核";
    String mCamera="默认品牌摄像头";
    
    public Director(Builder builder){
        mBuilder=builder;
    }
    
   //在这个方法里面调用builder相应的方法
    public void construct(String camera,String screen,String cpu){
        mBuilder.buildCamera(camera);
        mBuilder.builderScreen(screen);
        mBuilder.buildCpu(cpu);
        mBuilder.buildSystem();
        
    }
    
    public void construct(String camera){
        this.construct(camera, mScreen, mCPU);
        
    }
    
    public void construct(){
        this.construct(mCamera,mScreen,mCPU);
        
    }

}
public class TestBuilder {

    public static void main(String[] str){
        
        Builder builder = new SonyBuilder();
       //导演持有builder的引用
        Director director = new Director(builder);
        
        director.construct("索尼摄像头", "1280x720像素", "4核因特尔CPU");
        Phone phone = builder.creat();
        System.out.println(phone.toString());
        
        director.construct("索尼摄像头");
        Phone phone2 = builder.creat();
        System.out.println(phone2.toString());
        
        director.construct();
        Phone phone3 = builder.creat();
        System.out.println(phone3.toString());
        
    }
}

运行以上测试程序,将可以看到以下的输出结果

SonyPhone [mCPU=4核因特尔CPU, mCamera=索尼摄像头, mScreen=1280x720像素, mSystem=Android]
SonyPhone [mCPU=双核, mCamera=索尼摄像头, mScreen=1920x720, mSystem=Android]
SonyPhone [mCPU=双核, mCamera=默认品牌摄像头, mScreen=1920x720, mSystem=Android]

分析与讨论

director.construct("索尼摄像头", "2560*1920", "16核因特尔CPU");

综上所述,建造者模式的 优点可概括如下

在实际中的引用

其实在实际项目开发中,我们往往用不到上面的标准的Builder模式,因为我们的对象往往没有那么复杂,假如我们现在手机生产商只复制生产索尼手机,那Builder设计的UML图可以简略如下,去除Director。改为下面的链式调用。


SonyPhone phone=new SonyBuilder().buildCamera("索尼摄像机").buildCPU("8核").buildScreen("1280*720");

缺点

建造者模式所创建的产品一般具有较多的共同点,其组成部分相似,如果产品之间的差异性很大,则不适合使用建造者模式,因此其使用范围受到一定的限制。

适用场景


3)Builder在Android中源码的体现。

还记得我们平时在使用Dialog的时候的这种用法吗?

new AlertDialog.Builder(this).setCancelable(true)
        .setIcon(R.mipmap.app_logo).setMessage("温馨提醒").show();

哈哈,你是不是惊喜的发现这与我们上面简化的Builder模式几乎是一样的?没错,其实AlertDialog里面也使用了Builder模式

下面我们一起来看一下AlertDialog的源码

// AlertDialog
public class AlertDialog extends Dialog implements DialogInterface {
    // Controller, 接受Builder成员变量P中的各个参数
    private AlertController mAlert;

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

    // 4 : 构造AlertDialog
    AlertDialog(Context context, int theme, boolean createContextWrapper) {
        super(context, resolveDialogTheme(context, theme), createContextWrapper);
        mWindow.alwaysReadCloseOnTouchAttr();
        mAlert = new AlertController(getContext(), this, getWindow());
    }

    // 实际上调用的是mAlert的setTitle方法
    @Override
    public void setTitle(CharSequence title) {
        super.setTitle(title);
        mAlert.setTitle(title);
    }

    // 实际上调用的是mAlert的setCustomTitle方法
    public void setCustomTitle(View customTitleView) {
        mAlert.setCustomTitle(customTitleView);
    }

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

    // AlertDialog其他的代码省略
    
    

    // ************  Builder为AlertDialog的内部类   *******************
    public static class Builder {
        // 1 : 存储AlertDialog的各个参数, 例如title, message, icon等.
        private final AlertController.AlertParams P;
        // 属性省略


        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;
        }

        // Builder的其他代码省略 ......

        // 2 : 设置各种参数
        public Builder setTitle(CharSequence title) {
            P.mTitle = title;
            return this;
        }


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

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

        public Builder setPositiveButton(CharSequence text, final OnClickListener listener) {
            P.mPositiveButtonText = text;
            P.mPositiveButtonListener = listener;
            return this;
        }


        public Builder setView(View view) {
            P.mView = view;
            P.mViewSpacingSpecified = false;
            return this;
        }

        // 3 : 构建AlertDialog, 传递参数
        public AlertDialog create() {
            // 调用new AlertDialog构造对象, 并且将参数传递个体AlertDialog 
            final AlertDialog dialog = new AlertDialog(P.mContext, mTheme, false);
            // 5 : 将P中的参数应用的dialog中的mAlert对象中
            P.apply(dialog.mAlert);
            dialog.setCancelable(P.mCancelable);
            if (P.mCancelable) {
                dialog.setCanceledOnTouchOutside(true);
            }
            dialog.setOnCancelListener(P.mOnCancelListener);
            if (P.mOnKeyListener != null) {
                dialog.setOnKeyListener(P.mOnKeyListener);
            }
            return dialog;
        }
    }

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

4)Builder模式在ImageLoader和Rxjava中的体现

在ImageLoader中的体现

ImageLoaderConfiguration.Builder mBuilder = new ImageLoaderConfiguration    
    .Builder(this)  
    .threadPoolSize(3) //线程池内加载的数量    
    .threadPriority(Thread.NORM_PRIORITY - 2) //设置当前线程的优先级  
    .denyCacheImageMultipleSizesInMemory() //拒绝缓存同一图片的多个尺寸版本  
    .tasksProcessingOrder(QueueProcessingType.FIFO) //队列的排队算法,默认FIFO。FIFO表示先进先出,LIFO表示后进先出  
    .memoryCache(new UsingFreqLimitedMemoryCache(2 * 1024 * 1024)) //你可以通过自己的内存缓存实现    
    .memoryCacheSize(2 * 1024 * 1024) //使用的内存大小  
    .memoryCacheSizePercentage(13) //使用的内存百分比  
    .memoryCacheExtraOptions(480, 800) //设置内存中图片的长宽   
    .diskCache(new UnlimitedDiskCache(imageCacheDir)) //自定义磁盘的路径  
    .diskCacheSize(50 * 1024 * 1024) //使用的磁盘大小  
    .diskCacheFileCount(100) //磁盘的文件数量上限  
    .imageDecoder(new BaseImageDecoder(false)) //对图片解码,如需缩放或旋转可在此处理  
    .writeDebugLogs() //打印调试日志。上线时需要去掉该方法  
    ;  
ImageLoader.getInstance().init(mBuilder.build());  

在Rxjava中的体现

Network.getInstance()
        .getApi()
        .getSMS(phoneNumber,smsType)
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(new Action1<SMSBean>() {
            @Override
            public void call(SMSBean securityBean) {
                LUtils.e("" + securityBean.toString());
            
            }
        }, new Action1<Throwable>() {
            @Override
            public void call(Throwable throwable) {
           
                EventBus.getDefault().post(err, GET_VERIFYCODE_ERR_SETPHONENUMBER);
            }
        });


到此今天博客的分析为止


题外话

以前为了应付面试,显得自己比较厉害,有时候一天下来生硬地记下了好几个设计模式,关于各种设计模式的应用场景和优缺点,那时候刚开始的一两天还记得,可过了几天,知识就还给了书本,基本都忘记了,更谈不上运用。记得有一次去面试,问了一个我以前一直认为很简单的单例模式,那时候叫我写出几种单例模式,我嗖的一声就写出类, 饿汉式,懒汉式(双重锁定,静态内部类),登记式。但当面试官问到为什么要使用Synchronized Class而不使用Synchronized this,我竟然搭不上,我知道this是代表当前实例的引用,class是锁住整个Class类,但就是区分不出来。后面回来复习了才知道。

从那以后,我开始静下心来,不再为了变得牛逼而去学习某样东西,这样目的性太强的话我们往往会带有一些浮躁,刚开始的一两个月可能你还能坚持下来了,可一旦你发现你学习了这几样东西,其实你还是跟大多数人一样,这时候的你可能就会浮躁,开始沉不住气了。继而自己开始懈怠,慢慢地你会发现你很慢就坚持静下心来学习了。

一句话,技术这种东西急不来,常常太用力的人跑不远,因为他们往往很难坚持下来。所以,从现在开始,静下心来,一步一个脚印,享受生活,享受编程给我们带来的乐趣。

卖一下广告,有兴趣了解设计模式的,了、可以阅读下面我的两篇博客

装饰者模式及其应用

观察者设计模式 Vs 事件委托(java)

转载请注明原博客地址:

例子源码下载地址:

上一篇下一篇

猜你喜欢

热点阅读