Android中建造者(builder)模式

设计模式系列:
        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:被构造的复杂对象。         ---->GoodsBean
Builder:抽象接口。                ---->IGoods
BuilderImpl:抽象接口的具体实现。    ---->GoodsABuilder、GoodsBBuilder
Director:接口的构造者和使用者。     ---->Goods

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

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







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

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

猜你喜欢

转载自blog.csdn.net/u014769864/article/details/78135979