Android中建造者(builder)模式

来源:互联网 发布:2014matlab中对角矩阵 编辑:程序博客网 时间:2024/05/22 15:02

设计模式系列:
        0.Android开发常用设计模式;

        1. Android中单例模式;

        2. Android中建造者(builder)模式;

        3. Android中观察者模式;

        4. Android中原型模式;

        5. Android中策略模式;

        6.Android中工厂模式;

        7.Android中代理模式;

        8.Android中装饰者模式;

        9. Android中适配器模式;


一、常见需求场景

  三毛:“小白,你平常项目里使用建造者模式多不多”

这里写图片描述

  小白:建造者模式?毛毛哥,能说人话嘛

  三毛:“就是builder模式,链式调用那种”

  小白:思~索~片~刻~~,奥,你说的是下面这种吗,这面这样的链式形式我还没写过呢,只使用过,感觉挺清晰好看的

new AlertDialog.Builder(this)                .setTitle("对话框")                .setMessage("测试")                .setIcon(R.mipmap.ic_launcher)                .create()                .show();        Glide.with()                .load()                .into();        Picasso.with()                .load()                .into();


二、基本解决方法

  三毛:“不是吧,我的白,那你开发中例如遇到一个商品或用户注册有很多属性需要设置,你是怎么写的捏”

  小白:喔,这个简单,根据情况分2种写法,第一种是属性不多的时候使用构造方法,如果属性很多,那就用set和get,像下面酱紫:

//第一种(属性不是很多的时候) class 商品{     private String 属性1;//必传的参数     private String 属性2;//必传的参数     private String 属性3;//选传的参数       public 商品(属性1) {           this.(属性1)        }       public 商品(属性1,属性2,属性3) {           this.(属性1,属性2)        }              public 商品(属性1,属性2,属性3) {          this.属性1 = 属性1;          this.属性2 = 属性2;          this.属性3 = 属性3;        }    }//第二种(属性很多的时候)class 商品{ private String x1; private String x2; ......... public void setX1(String x1){ this.x1=x1; } public void setX2(String x2){ this.x2=x2; } public String getX1(){ return x1; public String getX2(){ return x2; } ......}


三、基本解决方法存在的问题

  三毛:“小白,你上面使用构造函数那一种写法,当使用者,用或看你的构造方法时,第一个,第二个,第三个参数很难知道要传什么或传的是什么,你要去查看才知道,同时,拓展和维护也会很迷糊的啵”

  小白:我吸口奶压压惊,老哥你继续

这里写图片描述

  三毛:“属性多的时候,使用set,get第二种方式,是解决了上面的问题,但是会让调用set方法的对象重复了20次或更多,同时也属于不连续的情况,该类的其他属性在被创建之后被修改,给程序带来了一些不安全性,像下面”

//属性越多,调用者(商品)重复越多商品.setX1("");商品.setX2("");商品.setX3("");.....//修改已经设置好了的某个属性商品.setX1("修改后的属性");

  小白:呐,毛毛哥,那应该怎么搞会好一点捏

四、变种Builder设计模式写法

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


  三毛:”你可以使用变种建造者(builder)模式试试,根据自己情况来”

  小白:等下,三毛哥,刚刚你说”变种”是啥子情况

  三毛:“建造者(builder)模式起初是有自己的标准的,后面随着时间推移,在这基础上Android演变出了变种建造者(builder)模式,不过Android中一般使用变种buildr模式就够用了,至于经典builder模式,类有点多,怕等下把你搞乱了,先说完变种Builder模式,后面在说经典builder模式”

  小白:那毛毛哥,你先告诉我变种builder模式怎么写

  三毛:“那就用前面那个例子吧,变种builder模式很简单的,主要是在类里建立一个静态内部类,像下面这样”

public class A {    private final String mX1;    private int mX2;    private A(Builder builder) {        mX1 = builder.mX1;        mX2 = builder.mX2;    }    public static final class Builder {        private final String mX1;        private int mX2;        public Builder() {        }        public Builder setX1(String val) {            mX1 = val;            return this;        }        public Builder setX2(int val) {            mX2 = val;            return this;        }        public A build() {            return new A(this);        }    }}//使用new A.Builder()      .setX1()      .setX2()      .build();

五、变种Builder模式和普通写法的区别


1、链式调用,结构清晰;
2、属性设置后,不会被修改,安全性较高;(也是变种builder基本不使用单例理由之一)
3、因为变种builder模式主要是以静态内部类实现,需求改变后,只需要替换新的静态内部类,原来的静态内部类可以原封不动,拓展性和维护较好








========================经典Builder模式分割线=====================

小白:这里写图片描述毛毛哥,快说,快说,啥是经典Builder模式

三毛:“这里写图片描述哇,小白你辣么可爱,咳咳咳!,下面说正事”

三毛:“有这样一个例子,‘有2个商品,它们都要经历生产-包装-标价过程‘,我的白,你用正常写法模拟下”

小白:毛毛哥,这还不简单,下面是我对上面的案例的模拟过程

//来个公用的接口public interface IGoods {     void produc();//生产商品     void packageGoods();//包装商品     void price();//给商品标价}//商品A类public class GoodsA implements IGoods{    @Override    public void produc() {        //生产商品A...        System.out.println("生产商品A……");    }    @Override    public void packageGoods() {        //包装商品A...        System.out.println("包装商品A……");    }    @Override    public void price() {        //给商品A标价...        System.out.println("给商品A标价……");    }    public void excuteOrder(){        produc();        packageGoods();        price();    }}//商品B和上面一模一样,就不贴重复代码了...//使用new GoodsA().excuteOrder();new GoodsB().excuteOrder();

小白:这里可以优化一下下,优化后代码

//把接口换成抽象类,把组装商品的过程放到这public abstract class IGoods {    abstract void produc();//生产商品    abstract void packageGoods();//包装商品    abstract void price();//给商品标价    //执行一条龙服务    public void excuteOrder(){        this.produc();//生产        this.packageGoods();//打包        this.price();//标价    }}//商品A类public class GoodsA extends IGoods{    @Override    public void produc() {        //生产商品A...        System.out.println("生产商品A……");    }    @Override    public void packageGoods() {        //包装商品A...        System.out.println("包装商品A……");    }    @Override    public void price() {        //给商品A标价...        System.out.println("给商品A标价……");    }}//商品B和上面一模一样,就不贴重复代码了...//使用new GoodsA().excuteOrder();new GoodsB().excuteOrder();

三毛:“可以哇,我的白,你上面其实就是经典Builder设计模式了,只不过不是完整的”

小白:啊,我不知不觉就用了经典Builder设计模式了?毛毛哥,那完整版是啥样子的,说来看看呗。

三毛:”不管怎样,首先你都要知道经典Builder模式有4个模块,如下。 “

//经典Builder 4个模块Product:被构造的复杂对象。Builder:抽象接口。BuilderImpl:抽象接口的具体实现。Director:接口的构造者和使用者。

三毛:”其实经典Builder模式只是比变种Builder模式复杂一点,下面我用经典Builder模式的形式完成你上面的案例,你可以和你的代码对比对比,有啥不同“

//实体类,也可以是其他业务类,看情况嘛public class GoodsBean {    private String producProcess;    private String packageProcess;    private String priceProcess;    private String goodsName;    public String getGoodsName() {        return goodsName;    }    public void setGoodsName(String goodsName) {        this.goodsName = goodsName;    }    public String getProducProcess() {        return producProcess;    }    public void setProducProcess(String producProcess) {        this.producProcess = producProcess;    }    public String getPackageProcess() {        return packageProcess;    }    public void setPackageProcess(String packageProcess) {        this.packageProcess = packageProcess;    }    public String getPriceProcess() {        return priceProcess;    }    public void setPriceProcess(String priceProcess) {        this.priceProcess = priceProcess;    }
//和你上面(没优化时)一样,只不过加了个获取商品类型的方法public interface IGoods {     void produc();//生产商品     void packageGoods();//包装商品     void price();//给商品标价     GoodsBean getGoodsType();//得到商品类型}
//还是和你上面一样,没啥子区别public class GoodsABuilder implements IGoods{    private GoodsBean goodsBean;    public GoodsABuilder() {        this.goodsBean = new GoodsBean();    }    @Override    public void produc() {        //生产商品A...        goodsBean.setProducProcess("生产商品A……");    }    @Override    public void packageGoods() {        //包装商品A...        goodsBean.setPackageProcess("包装商品A……");    }    @Override    public void price() {        //给商品A标价...        goodsBean.setPriceProcess("给商品A标价……");    }    @Override    public GoodsBean getGoodsType() {        goodsBean.setGoodsName("得到商品A……");        return goodsBean;    }//商品B一摸一样,就不贴重复代码了...}
//这是商品的组装类了public class Goods {    private IGoods mIGoods;    public Goods(IGoods mIGoods) {        this.mIGoods = mIGoods;    }    //执行一条龙服务    public void excuteOrder(){        mIGoods.produc();//生产        mIGoods.packageGoods();//打包        mIGoods.price();//标价    }}
  //使用  GoodsABuilder goodsABuilder = new GoodsABuilder();//得到商品构建对象     new Goods(goodsABuilder).excuteOrder();//组装商品     GoodsBean goodsType = goodsABuilder.getGoodsType();//最终得到某某商品     System.out.println(goodsType.getGoodsName());     //商品B和上面一摸一样,也不贴重复代码了     ...

小白:毛毛哥,你上面的代码对应经典Builder模式4个模块是下面这样的吗

Product:被构造的复杂对象。         ---->GoodsBeanBuilder:抽象接口。                ---->IGoodsBuilderImpl:抽象接口的具体实现。    ---->GoodsABuilder、GoodsBBuilderDirector:接口的构造者和使用者。     ---->Goods

三毛:”嗯,不错哇,我的白,理解那么快”

小白:嘿嘿,因为和我的想法一样嘛,虽然类有点多,不过每个模块职责挺清晰的,要是新加很多新商品,只需要添加对应的商品类(GoodsABuilder、GoodsBBuilder、GoodsCBuilder…)就好了,厉害了,我的哥。







总结:
  “经典Builder模式使得同样的构建过程可以创建不同的表示。像这里的商品都经历生产-包装-标价过程,但是每个商品都不同。”

  特点:
   1)封装性:使用建造者模式可以是客户端不必知道产品内部组成的细节。
   2)建造者独立,容易扩展:goodsABuilder和goodsBBuilder是相互独立的,对系统扩展非常有利。
   3)便于控制细节风险:由于具体的建造者是独立的,因此可以对建造者过程逐步细化,而不对其他的模块产生任何影响。

原创粉丝点击