建造者模式

建造者模式

定义

由于它是根据英文翻译而来,根据不同的翻译,建造者模式又可以称为生成器模式。它将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

​ 建造者模式是一步一步的来创建一个复杂的对象;该对象一般不会自己去构建具体的内容,而是通过属于自己建造者去构建;该建造者独立于其它的对象。

​ 我们在实际生活中开的汽车,就不是它自己组装的,它是通过汽车工人一步一步组装起来的;比如汽车一般会先完成汽车白身的焊接喷漆,然后安装发动机–安装底盘–安装线束–安装仪表板–安装内饰板–安装车门附件–安装发动机相关件–安装座椅–安装前后挡玻璃–安装其他附件—安装完成。一般在汽车制造企业会有一定安装顺序。当然不同的安装顺序会造成不同效果,比如你把其它的所有的东西都安装完了,然后再安装发动机,必然是不行的。

​ 在软件开发中,汽车工人就相当于我们的建造者,而我们想创建的对象就是汽车。我们通过建造者去创建一个我们想要的对象;并且创建步骤的不同会造成不同的结果,当然有好的结果,也有坏的结果。

组成角色

Product:我们创建/组装 的目标产品对象,我们需要通过建造者模式最终创建的对象。这个可以是抽象的也可以是具体的。

Builder:一般为抽象类或者接口,为了规范产品的创建,它会包含创建产品的步骤,然后由子类去实现每个步骤具体的行为。

ConcreteBuilder:Builder的子类;由它实现Builder类/接口的具体实现。

Director:指挥者。由它来安排产品的创建/组装的具体步骤。它就相当于汽车工厂的车间主任。

它的结构图如下:

时序图如下:

具体示例

我们以汽车为例,我们只列出其中几个关键的步骤。

我们会创建奔驰和宝马汽车。一夜之间成为高富帅。

  • 首先我们创建抽象的一个汽车类;用来抽取奔驰和宝马的共同特征;它是我们创建的产品的抽象类。

    public abstract class Car {
    
      //品牌
      protected String mBrand;
      //发动机
      protected String mEngine;
      //底盘
      protected String mUnderpan;
      //方向盘
      protected String mStreetingWheel;
      //座椅
      protected String mSeat;
    
      public Car() {
      }
    
      public abstract void setBrand(String brand);
    
      public void setEngine(String engine) {
          mEngine = engine;
      }
    
      public void setSeat(String seat) {
          mSeat = seat;
      }
    
      public void setStreetingWheel(String streetingWheel) {
          mStreetingWheel = streetingWheel;
      }
    
      public void setUnderpan(String underpan) {
          mUnderpan = underpan;
      }
    
      @Override
      public String toString() {
          return "Car{" +
                  "mBrand='" + mBrand + '\'' +
                  ", mEngine='" + mEngine + '\'' +
                  ", mUnderpan='" + mUnderpan + '\'' +
                  ", mStreetingWheel='" + mStreetingWheel + '\'' +
                  ", mSeat='" + mSeat + '\'' +
                  '}';
      }
    }
  • 然后我们创建 奔驰和宝马车;它们是我们创建的具体产品

    public class BenzCar extends Car {
    
      @Override
      public void setBrand(String brand) {
          this.mBrand = brand;
      }
    }
    public class BmwCar extends Car {
    
      @Override
      public void setBrand(String brand) {
          this.mBrand = brand;
      }
    }
  • 其后我们创建抽象汽车建造者;由来抽取汽车建造的共同点

    public abstract class CarBuilder {
    
      //安装品牌车标
      public abstract void buildBrand(String brand);
    
      //安装发动机
      public abstract void buildEngine();
    
      //安装底盘
      public abstract void buildUnderpan();
    
      //安装方向盘
      public abstract void buildSteeringWheel();
    
      //安装座椅
      public abstract void buildSeat();
    
      //最后完成安装
      public abstract Car create();
    
    }
  • 接下来创建具体的奔驰和宝马建造者

    public class BenzCarBuilder extends CarBuilder {
    
      Car mCar = new BenzCar();
    
      @Override
      public void buildBrand(String brand) {
          mCar.setBrand(brand);
      }
    
      @Override
      public void buildEngine() {
          mCar.setEngine("奔驰发动机");
      }
    
      @Override
      public void buildUnderpan() {
          mCar.setUnderpan("奔驰底盘");
      }
    
      @Override
      public void buildSteeringWheel() {
          mCar.setStreetingWheel("奔驰方向盘");
      }
    
      @Override
      public void buildSeat() {
          mCar.setSeat("奔驰座椅");
      }
    
      @Override
      public Car create() {
          return mCar;
      }
    }
    public class BmwCarBuilder extends CarBuilder {
    
      Car mCar = new BmwCar();
    
      @Override
      public void buildBrand(String brand) {
          mCar.setBrand(brand);
      }
    
      @Override
      public void buildEngine() {
          mCar.setEngine("宝马发动机");
      }
    
      @Override
      public void buildUnderpan() {
          mCar.setUnderpan("宝马底盘");
      }
    
      @Override
      public void buildSteeringWheel() {
          mCar.setStreetingWheel("宝马方向盘");
      }
    
      @Override
      public void buildSeat() {
          mCar.setSeat("宝马座椅");
      }
    
      @Override
      public Car create() {
          return mCar;
      }
    }
  • 最后我们创建一个指挥者来建造不同车

    public class Director {
    
      private CarBuilder mCarBuilder = null;
    
          public Director(CarBuilder carBuilder) {
          mCarBuilder = carBuilder;
      }
    
      public Car construct(String brand) {
          mCarBuilder.buildBrand(brand);
          mCarBuilder.buildEngine();
          mCarBuilder.buildUnderpan();
          mCarBuilder.buildSteeringWheel();
          mCarBuilder.buildSeat();
          return mCarBuilder.create();
      }
    }

做完上面的事情,建造者模式其实已经完了,我们来测试一下:

public static void main(String[] args) {
    CarBuilder bmwCarBuilder = new BmwCarBuilder();
    Director bmwDirector = new Director(bmwCarBuilder);
    Car bmwCar = bmwDirector.construct("宝马车标");

    System.out.println(bmwCar);

    CarBuilder benzCarBuilder = new BenzCarBuilder();
    Director benzDirector = new Director(benzCarBuilder);
    Car benzCar = benzDirector.construct("奔驰车标");

    System.out.println(benzCar);
}

输出结果为:

Car{mBrand=’宝马车标’, mEngine=’宝马发动机’, mUnderpan=’宝马底盘’, mStreetingWheel=’宝马方向盘’, mSeat=’宝马座椅’}

Car{mBrand=’奔驰车标’, mEngine=’奔驰发动机’, mUnderpan=’奔驰底盘’, mStreetingWheel=’奔驰方向盘’, mSeat=’奔驰座椅’}

这样我们就通过把汽车的创建过程拆分,并且使用不同的建造者建造了不同的汽车。

模式扩展

上面的建造者模式其实还是有些复杂,它还可以做一些简化,

  • 省略抽象建造者: 很多情况下是不需要抽象建造者的,所以我们只需要一个具体的建造者就OK。
  • 省略指挥者:既然没有抽象的建造者,指挥者存在的意义也就不大了,所以我们把指挥者的省略掉,并将其功能合并到具体建造者中。

我们看一个具体的例子,我们还是以汽车为例,这里我们以Jeep为例,我们只使用一个类来完成。

public class JeepCar extends Car {

    public JeepCar() {
    }

    @Override
    public void setBrand(String brand) {
        this.mBrand = brand;
    }

    public static class Builder {
        JeepCar mCar = new JeepCar();

        public void buildBrand(String brand) {
            mCar.setBrand(brand);
        }

        public void buildEngine() {
            mCar.setEngine("Jeep 发动机");
        }

        public void buildUnderpan() {
            mCar.setUnderpan("Jeep 底盘");
        }

        public void buildSteeringWheel() {
            mCar.setStreetingWheel("Jeep 方向盘");
        }

        public void buildSeat() {
            mCar.setSeat("Jeep座椅");
        }

        public JeepCar create() {
            buildBrand("Jeep 车标");
            buildEngine();
            buildUnderpan();
            buildSteeringWheel();
            buildSeat();
            return mCar;
        }
    }
}

我们将具体的建造者放到了JeepCar 的内部作为内部类;并且将指挥者的功能合并到建造者的 create() 方法内。

下面我们来测试一下:

public static void main(String[] args) {
    JeepCar.Builder builder = new JeepCar.Builder();
    JeepCar jeepCar = builder.create();

    System.out.println(jeepCar);
}

输出为:

Car{mBrand=’Jeep 车标’, mEngine=’Jeep 发动机’, mUnderpan=’Jeep 底盘’, mStreetingWheel=’Jeep 方向盘’, mSeat=’Jeep座椅’}

上面的例子其实跟Android中的AlertDaliog 很像,它也是讲Builder作为内部类,并将创建过程来放到了Builder内部。如果我们需要自定义一个Dialog 的话可以参考一下:

比如我们自定义一个简单的LoadingDialog:

public class LoadingDialog extends Dialog {

    private LoadingDialog(Context context) {
        super(context);
    }

    public LoadingDialog(Context context, int theme) {
        super(context, theme);
    }

    protected LoadingDialog(Context context, boolean cancelable, OnCancelListener cancelListener) {
        super(context, cancelable, cancelListener);
    }

    public static class Builder {
        private LoadingDialog mDialog = null;
        private Activity mActivity;
        private LayoutInflater mInflater;
        private View mContentView;

        public Builder(Activity activity) {
            mActivity = activity;
            mInflater = LayoutInflater.from(mActivity);
        }

        public LoadingDialog create() {
            mDialog = new LoadingDialog(mActivity, R.style.LoadingDialog);
            mContentView = mInflater.inflate(R.layout.haima_dialog_loading, null);
            // 取消title占位
            mDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
            mDialog.setCancelable(false);
            // 取消原生背景颜色
            mDialog.getWindow().setBackgroundDrawable(new ColorDrawable(0));
            mDialog.setCanceledOnTouchOutside(false);
            mDialog.setContentView(mContentView);
            return mDialog;
        }
    }
}

我们可以这样使用:

LoadingDialog.Builder loadingBuilder = new LoadingDialog.Builder(activity);
LoadingDialog loadingDialog = loadingBuilder.create();
loadingDialog.show();//显示
loadingDialog.dismiss();//取消显示

优点

  • 在建造者模式中,调用者/用户 不需要知道产品的内部组成,将产品本身和产品的创建过程解耦;甚至可以使得不同的创建过程可以创建不同的产品对象。
  • 每一个具体的创建者都是相对独立的。我们可以很方便的替换具体建造者,或者添加新的建造者;用户可以使用不同的建造者创建不同的产品对象
  • 建造者将产品的创建过程细化分解,可以更精细的控制产品的创建过程。
  • 增加新的具体建造者无须修改原有类库的代码,指挥者类针对抽象建造者类编程,系统扩展方便,符合“开闭原则”。

缺点

  • 建造者模式一般具有较多的共同点,比如上面的汽车,各个汽车之间共同点很多。其组成部分相似,如果产品之间的差异性很大,则不适合使用建造者模式,因此其使用范围受到一定的限制。
  • 如果产品的内部变化复杂,可能会导致需要定义很多具体建造者类来实现这种变化,导致系统变得很庞大。

使用场景

  • 需要创建的产品内部比较复杂,这些产品通常有多个成员属性
  • 需要生成的产品对象的属性相互依赖,需要制定其生成顺序;甚至不同的顺序会产生不同的结果
  • 隔离复杂对象的创建和使用,并使得相同的创建过程可以创建不同的产品。
  • 如果一个对象的在初始化的时候参数太多,也可以使用构造者模式。

本文参考:http://design-patterns.readthedocs.io/zh_CN/latest/creational_patterns/builder.html

本文中的结构图和时序图来自:http://design-patterns.readthedocs.io/zh_CN/latest/creational_patterns/builder.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值