建造者模式
概述
建造者模式属于创建型模式,提供了一种创建对象的最佳方式
定义:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
作用:在用户不知道对象的建造过程和细节的情况下就可以直接创建复杂的对象。
用户只需要给出指定复杂对象的类型和内容,建造者模式负责按顺序创建复杂对象(把内部的建造过程和细节隐藏起来)
建造者模式中包含如下几个角色:
① Builder(抽象建造者):它为创建一个产品Product对象的各个部件指定抽象接口,在该接口中一般声明两类方法,一类方法是buildPartX(),它们用于创建复杂对象的各个部件,另一个类方法时getResult(),用于返回复杂对象。Builder可以是抽象类,也可以是接口。
② ConcreteBuilder(具体建造者):它实现了Builder接口,实现各个部件的具体构造和装配方法。定义并明确它所创建的复杂对象,也可以提供一个方法返回创建好的复杂产品对象。
③ Product(产品角色):是被构建的复杂对象。包含多个组成部件,具体即按照这创建该产品的内部表示并定义它的装配过程。
④ Director(指挥者):指挥者又称为导演类,它负责安排复杂对象的建造次序,指挥者与抽象建造者之间存在关联关系,可以在其construct()建造方法中调用建造者对象的部件构造与装配方法,完成复杂对象的建造。客户端一般只需要与指挥者进行交互。
举例
下面我们来举一个例子,通过这个例子理解一下建造者模型。
汽车是一种复杂的对象,它由许多部件组成,一种品牌的汽车,可以有不同的车型,比如奥迪旗下车型有:RS7、A6等等。不同的车型使用到的部件也是不同的,我们使用建造者模型,来模拟以下这两款车型的建造过程。
图示:
首先是Builder类(抽象建造者):定义了如何创建不同车型,以及部件的装配顺序。
// 抽象的建造者:定义一些方法
public abstract class Builder {
abstract void buildEngine(); //建造发动机
abstract void buildChassis(); //建造底盘
abstract void buildCarBody(); //建造车身
abstract void buildElectrical();// 建造电气设备
abstract void buildWheel(); //造车轮
abstract Product getProduct(); //返回创建好的产品
}
Product类(产品类):指明各车型需要的部件。
// 产品类:表明该产品所需的零件。
public class Product {
private String engine; //发动机
private String carBody; //车身
private String electricalElement; //电气设备
private String chassis;//底盘
private String wheel;//车轮
public String getWheel() {
return wheel;
}
public void setWheel(String wheel) {
this.wheel = wheel;
}
public String getEngine() {
return engine;
}
public void setEngine(String engine) {
this.engine = engine;
}
public String getCarBody() {
return carBody;
}
public void setCarBody(String carBody) {
this.carBody = carBody;
}
public String getElectricalElement() {
return electricalElement;
}
public void setElectricalElement(String electricalElement) {
this.electricalElement = electricalElement;
}
public String getChassis() {
return chassis;
}
public void setChassis(String chassis) {
this.chassis = chassis;
}
@Override
public String toString() {
return "Product{" +
"engine='" + engine + '\'' +
", carBody='" + carBody + '\'' +
", electricalElement='" + electricalElement + '\'' +
", chassis='" + chassis + '\'' +
", wheel='" + wheel + '\'' +
'}';
}
}
ConcreteBuilder(具体建造者):根据不同车型,使用不同的部件建造车。
//具体建造A6车型:
public class AudiA6Builder extends Builder {
private Product product;
public AudiA6Builder(){
product = new Product();
}
@Override
void buildEngine() {
product.setEngine("2.0T L4发动机");
}
@Override
void buildChassis() {
product.setChassis("前置前驱,多片离合器");
}
@Override
void buildCarBody() {
product.setCarBody("普通三厢车车身");
}
@Override
void buildElectrical() {
product.setElectricalElement("蓄电池");
}
@Override
void buildWheel() {
product.setWheel("225/55 R18");
}
@Override
Product getProduct() {
return product;
}
}
//具体建造RS7车型
public class AudiRS7Builder extends Builder {
private Product product;
public AudiRS7Builder(){
product = new Product();
}
@Override
void buildEngine() {
product.setEngine("V8发动机");
}
@Override
void buildChassis() {
product.setChassis("前置四驱、机械扭矩限滑差速锁");
}
@Override
void buildCarBody() {
product.setCarBody("掀背");
}
@Override
void buildElectrical() {
product.setElectricalElement("蓄电池");
}
@Override
void buildWheel() {
product.setWheel("275/35 R21");
}
@Override
Product getProduct() {
return product;
}
}
Director(指挥者):通过智慧Builder,来获取相应的车型。
public class Director {
public Product construct(Builder builder){
builder.buildCarBody();
builder.buildChassis();
builder.buildElectrical();
builder.buildEngine();
builder.buildWheel();
Product product = builder.getProduct();
return product;
}
}
测试类:
public class test {
public static void main(String[] args) {
Director director = new Director();
// 建造奥迪RS7
Product rs7 = director.construct(new AudiRS7Builder());
System.out.println(rs7);
// 建造奥迪A6
Product a6 = director.construct(new AudiA6Builder());
System.out.println(a6);
}
}
测试结果:
上面的例子,是我们建造者模型的常规的样子,为了简化结构,我们可以将Director和Builder合并,将Builder类作为Product类的静态内部类
代码如下:
public class Product {
private String engine; //发动机
private String carBody; //车身
private String electricalElement; //电气设备
private String chassis;//底盘
private String wheel;//车轮
public String getEngine() {
return engine;
}
public String getCarBody() {
return carBody;
}
public String getElectricalElement() {
return electricalElement;
}
public String getChassis() {
return chassis;
}
public String getWheel() {
return wheel;
}
public static class Builder{
private Product product = new Product();
public Builder setEngine(String engine){
product.engine = engine;
return this;
}
public Builder setCarBody(String carBody){
product.carBody = carBody;
return this;
}
public Builder setElectricalElement(String electricalElement){
product.electricalElement = electricalElement;
return this;
}
public Builder SetChassis(String chassis){
product.chassis = chassis;
return this;
}
public Builder setWheel(String wheel){
product.wheel = wheel;
return this;
}
public Product getProduct(){
return product;
}
}
@Override
public String toString() {
return "Product{" +
"engine='" + engine + '\'' +
", carBody='" + carBody + '\'' +
", electricalElement='" + electricalElement + '\'' +
", chassis='" + chassis + '\'' +
", wheel='" + wheel + '\'' +
'}';
}
}
客户端代码:
public class test {
public static void main(String[] args) {
Product.Builder rs7Builder = new Product.Builder();
Product product = rs7Builder.setCarBody("掀背").
SetChassis("前置四驱").
setElectricalElement("蓄电池").
setEngine("V8发动机").setWheel("275/35 R21").getProduct();
System.out.println(product);
}
}
这样,直接省略了Director类和ConcreteBuilder类,但是,在我看来,这样建造出来的产品,并没有对用户隐藏建造产品的细节,而是将这个产品是由什么样的部件创建的全部展示出来,违背了建造者模式的初衷。
所以我修改了一下代码,我继续添加了ConcreteBuilder:
public class AudiRs7Builder {
public Product getProduct(){
Product.Builder rs7Builder = new Product.Builder();
return rs7Builder.setCarBody("掀背").
SetChassis("前置四驱").
setElectricalElement("蓄电池").
setEngine("V8发动机").setWheel("275/35 R21").getProduct();
}
}
public class test {
public static void main(String[] args) {
AudiRs7Builder audiRs7Builder = new AudiRs7Builder();
Product product = audiRs7Builder.getProduct();
System.out.println(product);
}
}
这样,就完美的解决了刚才的尴尬了。我们将Director类省略,也可以使用建造者模型。
建造者模式优缺点
建造者模式的优点:
① 客户端不必知道产品内部组成的细节,将产品本身与产品的创建过程解耦,使得相同的常见过程可以创建不同的产品对象。
② 每一个具体建造者都相对独立,与其他具体建造者无关,因此可以很方便地替换具体建造者或增加新的建造者,用户使用不同的具体建造者即可得到不同的产品对象。
③ 可以更加精细第控制产品的创建过程。
建造者模式的缺点:
① 建造者模式所创建的产品一般具有较多的共同点,其组成部分相似,如果产品间差异很大,不适用建造者模式
② 如果产品内部变化复杂,可能导致需要定义很多建造者类来实现这种变化,增加系统的理解程度和运行成本。
区分建造者模式和抽象工厂模式
与抽象工厂模式相比,建造者模式返回一个组装好的完整产品,而抽象工厂模式返回一系列就相关的产品,这些产品位于不同的产品等级结构,构成了一个产品族。
在抽象工厂模式中,客户端实例化工厂类,然后调用工厂方法获取所需的产品对象,而在建造者模式中,客户端可以不直接调用建造者相关方法,而是通过指挥者类指导如何生成对象,它侧重于一步步构造一个复杂对象,返回一个完整的对象。