在软件开发过程中有时需要创建一个复杂的对象,这个复杂对象通常由多个子部件按一定的步骤组合而成。
例如,计算机是由 CPU、主板、内存、硬盘、显卡、机箱、显示器、键盘、鼠标等部件组装而成的,采购员不能自己组装,而是交给计算机公司完成。
与之相似的案例非常多,比如汽车由方向盘、发动机、车架、轮胎等部件组成。游戏中的角色由性别、个性、能力、脸型、体型、服装、发型等部件组成。
特点与定义
- 定义:
指将一个复杂对象的构造与它的表示分离,使同样的构建过程可以创建不同的表示,这样的设计模式被称为建造者模式。它是将一个复杂的对象分解为多个简单的对象,然后一步一步构建而成。它将变与不变相分离,即产品的组成部分是不变的,但每一部分是可以灵活选择的。
参与角色
- 产品角色(Product):包含多个组成部件的复杂对象,由具体建造者来创建其各个零部件。
- 抽象建造者(Builder):一个包含创建产品各个子部件的抽象方法的接口,通常还包含一个返复杂产品的方法 getResult()。
- 具体建造者(Concrete Builder):抽象建造者子类,完成复杂产品的各个部件的具体创建方法。
- 指挥者(Director):它调用建造者对象中的部件构造与装配方法完成复杂对象的创建,在指挥者中不涉及具体产品的信息。主要有两个作用,一是:隔离了客户与对象的生产过程,二是:负责控制产品对象的生产过程。
- 结构类图
结构代码示例
复杂对象(产品)
public class Product { private String partA; //可以是任意类型 private String partB; private String partC; //partA的Getter方法和Setter方法省略 //partB的Getter方法和Setter方法省略 //partC的Getter方法和Setter方法省略 }
抽象建造者
public abstract class Builder{ protected Product product = new Product(); public abstract void buildPartA(); public abstract void buildPartB(); public abstract void buildPartC(); public Product getResult(){ return product; } }
具体建造者。实现抽象接口,构建和装配各个部件
public class ConcreteBuilder extends Builder{ public void buildPartA(){ ... } public void buildPartB(){ ... } public void buildPartC(){ ... } }
指挥者
public class Director{ private Builder builder; //1 构造方法的方式注入builder对象 public Director(Builder builder){ this.builder=builder; } //2 set方法注入builder对象 public void setBuilder(Builder builder){ this.builder=builer; } public Product construct(){ builder.buildPartA(); builder.buildPartB(); builder.buildPartC(); return builder.getResult(); } }
客户端调用
…… Builder builder = new ConcreteBuilder(); Director director = new Director(builder); Product product = director.construct(); ……
模式案例分析
我们用制造自行车为例子讲解建造者模式,自行车由车架、轮胎、脚踏等部件组成。自行车制造公司就是把这些零部件组装起来。这里我们以自行车建造为例。
自行车制造公司的工程部门相当于指挥者,生产部门相当于建造者,摩拜和ofo相当于客户,单车就是产品。
定义自行车(复杂产品)
public class Bike { // 轮胎 private String tyre; // 车架 private String frame; // GPS定位装置 private String gps; //getter&setter省略 }
定义生产线(抽象建造者)
//生产线(抽象建造者) interface BikeBuilder { // 组装轮胎 public void buildTyres(); // 组装车架 public void buildFrame(); // 组装GPS定位装置 public void buildGPS(); // 获取自行车,getResult方法 public Bike getBike(); }
定义摩拜单车生产线(具体建造者)
class MoBikeBuilder implements BikeBuilder { // 拥有单车对象 Bike bike = new Bike(); @Override public void buildTyres() { bike.setTyre("橙色轮胎"); } @Override public void buildFrame() { bike.setFrame("橙色车架"); } @Override public void buildGPS() { bike.setGps("mobike定制版GPS定位装置"); } @Override public Bike getBike() { return bike; } }
定义ofo单车生产线(具体建造者)
class OfoBikeBuilder implements BikeBuilder { // 拥有单车对象 Bike bike = new Bike(); @Override public void buildTyres() { bike.setTyre("黑色轮胎"); } @Override public void buildFrame() { bike.setFrame("黄色车架"); } @Override public void buildGPS() { bike.setGps("ofo定制版GPS定位装置"); } @Override public Bike getBike() { return bike; } }
定义工程部(指挥者、监工)
//工程部(指挥者、监工) class EngineeringDepartment { // 用户告知指挥者想要什么样的单车 BikeBuilder bikeBuilder; public EngineeringDepartment(BikeBuilder bikeBuilder){ this.bikeBuilder = bikeBuilder; } // 指导组装单车 public void construct(){ bikeBuilder.buildTyres(); bikeBuilder.buildFrame(); bikeBuilder.buildGPS(); } }
测试类
class Test { public static void main(String[] args) { // 建造摩拜单车 BikeBuilder moBikeBuilder = new MoBikeBuilder(); EngineeringDepartment ed1 = new EngineeringDepartment(moBikeBuilder); ed1.Construct();// 指导组装 // 产出单车,体现建造和显示分离 Bike moBike = moBikeBuilder.getBike(); // 建造ofo单车 BikeBuilder ofoBikeBuilder = new MoBikeBuilder(); EngineeringDepartment ed2 = new EngineeringDepartment(ofoBikeBuilder); ed2.Construct();// 指导组装 Bike ofoBike = ofoBikeBuilder.getBike(); } }
总结
优点
- 产品的建造和表示分离,实现了解耦。
- 隐藏了产品的建造细节,用户只需关心产品的表示,而不需要了解是如何创建产品的。
- 体现了开闭原则,如上代码所示,如果需要再生产其他共享单车,只需要再开一条生产线即可,不影响其他生产线的作业。
缺点
- 产品的组成部分必须相同,这限制了其使用范围。
- 当建造者过多时,会产生很多类,难以维护。