建造者模式
来源:互联网 发布:sunrise软件 编辑:程序博客网 时间:2024/06/08 19:17
建造者模式
定义
由于它是根据英文翻译而来,根据不同的翻译,建造者模式又可以称为生成器模式。它将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
建造者模式是一步一步的来创建一个复杂的对象;该对象一般不会自己去构建具体的内容,而是通过属于自己建造者去构建;该建造者独立于其它的对象。
我们在实际生活中开的汽车,就不是它自己组装的,它是通过汽车工人一步一步组装起来的;比如汽车一般会先完成汽车白身的焊接喷漆,然后安装发动机–安装底盘–安装线束–安装仪表板–安装内饰板–安装车门附件–安装发动机相关件–安装座椅–安装前后挡玻璃–安装其他附件—安装完成。一般在汽车制造企业会有一定安装顺序。当然不同的安装顺序会造成不同效果,比如你把其它的所有的东西都安装完了,然后再安装发动机,必然是不行的。
在软件开发中,汽车工人就相当于我们的建造者,而我们想创建的对象就是汽车。我们通过建造者去创建一个我们想要的对象;并且创建步骤的不同会造成不同的结果,当然有好的结果,也有坏的结果。
组成角色
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
- Builder 建造者模式
- 建造者模式
- 设计模式-------建造者
- 建造者模式
- 建造者模式(Builder)
- 建造者模式(Builder)
- 建造者模式
- 建造者模式 - builder
- 建造者模式
- Builder建造者模式
- 建造者模式(Builder)
- 建造者模式(builder)
- 建造者模式
- java建造者模式
- 建造者模式
- 建造者模式
- 建造者模式(Builder)
- 建造者模式
- ssh的安装
- 蓝桥杯 ALGO-102 算法训练 数对
- 哈哈哈哈哈哈哈哈哈
- 【OpenCV入门指南】第二篇 缩放图像
- 零基础入门深度学习(5)
- 建造者模式
- svn出错:Previous operation has not finished; run 'cleanup' if it was interrupted
- MFC 如何改变对话框的默认背景颜色
- 蓝桥杯 ALGO-100 算法训练 整除问题
- orginalEvent是什么,有什么用处,jquery不是万能的
- 详解反调试技术
- linux下查看swap占用情况
- 蓝桥杯 ALGO-99 算法训练 薪水计算
- JAVA中堆和栈的区别