创建类模式大PK

Posted gendway

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了创建类模式大PK相关的知识,希望对你有一定的参考价值。


创建类模式包括工厂方法模式、 建造者模式、 抽象工厂模式、 单例模式和原型模式, 它
们都能够提供对象的创建和管理职责。 其中的单例模式和原型模式非常容易理解, 单例模式
是要保持在内存中只有一个对象, 原型模式是要求通过复制的方式产生一个新的对象, 这两
个不容易混淆。 剩下的就是工厂方法模式、 抽象工厂模式和建造者模式了, 这三个之间有较
多的相似性。
30.1 工厂方法模式VS建造者模式
工厂方法模式注重的是整体对象的创建方法, 而建造者模式注重的是部件构建的过程,
旨在通过一步一步地精确构造创建出一个复杂的对象。 我们举个简单例子来说明两者的差
异, 如要制造一个超人, 如果使用工厂方法模式, 直接产生出来的就是一个力大无穷、 能够
飞翔、 内裤外穿的超人; 而如果使用建造者模式, 则需要组装手、 头、 脚、 躯干等部分, 然
后再把内裤外穿, 于是一个超人就诞生了。 纯粹使用文字来描述比较枯燥, 我们还是通过程
序来更加清晰地认识两者的差别。
30.1.1 按工厂方法建造超人
首先, 按照工厂方法模式创建出一个超人, 类图如图30-1所示。图30-1 按工厂方法建造超人
类图中我们按照年龄段把超人分为两种类型: 成年超人(如克拉克、 超能先生) 和未成
年超人(如Dash、 Jack) 。 这是一个非常正宗的工厂方法模式, 定义一个产品的接口, 然后
再定义两个实现, 通过超人制造工厂制造超人。 想想看我们对超人最大印象是什么? 当然是
他的超能力, 我们以specialTalent(特殊天赋) 方法来代表, 先看抽象产品类, 如代码清单
30-1所示。
代码清单30-1 超人接口
public interface ISuperMan {
//每个超人都有特殊技能
public void specialTalent();
}产品的接口定义好了, 我们再来看具体的产品。 先看成年超人, 很简单, 如代码清单
30-2所示。
代码清单30-2 成年超人
public class AdultSuperMan implements ISuperMan {
//超能先生
public void specialTalent() {
System.out.println("超人力大无穷");
}
}
未成年超人的代码如代码清单30-3所示。
代码清单30-3 未成年超人
public class ChildSuperMan implements ISuperMan {
//超能先生的三个孩子
public void specialTalent() {
System.out.println("小超人的能力是刀枪不入、 快速运动");
}
}
产品都具备, 那我们编写一个工厂类, 其意图就是生产超人, 具体是成年超人还是未成
年超人, 则由客户端决定, 如代码清单30-4所示。
代码清单30-4 超人制造工厂
public class SuperManFactory {
//定义一个生产超人的工厂
public static ISuperMan createSuperMan(String type){
//根据输入参数产生不同的超人
if(type.equalsIgnoreCase("adult")){
//生产成人超人
return new AdultSuperMan();
}else if(type.equalsIgnoreCase("child")){
//生产未成年超人
return new ChildSuperMan();
}else{
return null;
}
}
}
产品有了, 工厂类也有了, 剩下的工作就是开始生产超人。 这也非常简单, 如代码清单30-5所示。
代码清单30-5 场景类
public class Client {
//模拟生产超人
public static void main(String[] args) {
//生产一个成年超人
ISuperMan adultSuperMan = SuperManFactory.createSuperMan("adult");
//展示一下超人的技能
adultSuperMan.specialTalent();
}
}
建立了一个超人生产工厂, 年复一年地生产超人, 对于具体生产出的产品, 不管是成年
超人还是未成年超人, 都是一个模样: 深蓝色紧身衣、 胸前S标记、 内裤外穿, 没有特殊的
地方。 但是我们的目的达到了——生产出超人, 拯救全人类, 这就是我们的意图。 具体怎么
生产、 怎么组装, 这不是工厂方法模式要考虑的, 也就是说, 工厂模式关注的是一个产品整
体, 生产出的产品应该具有相似的功能和架构。
注意 通过工厂方法模式生产出对象, 然后由客户端进行对象的其他操作, 但是并不代
表所有生产出的对象都必须具有相同的状态和行为, 它是由产品所决定。
30.1.2 按建造者模式建造超人
我们再来看看建造者模式是如何生产超人的,如图30-2所示。图30-2 按建造者模式生产超人
又是一个典型的建造者模式! 哎, 不对呀! 通用模式上抽象建造者与产品类没有关系
呀! 是的, 我们当然可以加强了, 我们在抽象建造者上使用了模板方法模式, 每一个建造者
都必须返回一个产品, 但是产品是如何制造的, 则由各个建造者自己负责。 我们来看看程
序, 先看产品类, 如代码清单30-6所示。
代码清单30-6 超人产品
public class SuperMan {
//超人的躯体
private String body;
//超人的特殊技能
private String specialTalent;
//超人的标志
private String specialSymbol;
public String getBody() {
return body;
}p
ublic void setBody(String body) {
this.body = body;
}p
ublic String getSpecialTalent() {
return specialTalent;
}p
ublic void setSpecialTalent(String specialTalent) {
this.specialTalent = specialTalent;
}p
ublic String getSpecialSymbol() {
return specialSymbol;
}p
ublic void setSpecialSymbol(String specialSymbol) {
this.specialSymbol = specialSymbol;
}}
超人这个产品是由三部分组成: 躯体、 特殊技能、 身份标记, 这就类似于电子产品, 首
先生产出一个固件, 然后再安装一个灵魂(软件驱动) , 最后再打上产品标签。 完事了! 一
个崭新的产品就诞生了! 我们的超人也是这样生产的, 先生产一个普通的躯体, 然后注入特
殊技能, 最后打上S标签, 一个超人生产完毕。 我们再来看一下建造者的抽象定义, 如代码
清单30-7所示。
代码清单30-7 抽象建造者
public abstract class Builder {
//定义一个超人的应用
protected final SuperMan superMan = new SuperMan();
//构建出超人的躯体
public void setBody(String body){
this.superMan.setBody(body);
}/
/构建出超人的特殊技能
public void setSpecialTalent(String st){
this.superMan.setSpecialTalent(st);
}/
/构建出超人的特殊标记
public void setSpecialSymbol(String ss){
this.superMan.setSpecialSymbol(ss);
}/
/构建出一个完整的超人
public abstract SuperMan getSuperMan();
}
一个典型的模板方法模式, 超人的各个部件(躯体、 灵魂、 标志) 都准备好了, 具体怎
么组装则是由实现类来决定。 我们先来看成年超人, 如代码清单30-8所示。
代码清单30-8 成年超人建造者
public class AdultSuperManBuilder extends Builder {
@Override
public SuperMan getSuperMan() {
super.setBody("强壮的躯体");
super.setSpecialTalent("会飞行");
super.setSpecialSymbol("胸前带S标记");
return super.superMan;
}
}
怎么回事? 在第11章中讲解建造者模式的时候在产品中使用了模板方法模式, 在这里怎么把模板方法模式迁移到建造者了? 怎么会这样? 你是不是在发出这样的疑问? 别疑问了!
设计模式只是提供了一个解决问题的意图: 复杂对象的构建与它的表示分离, 而没有具体定
出一个设计模式必须是这样的实现, 必须是这样的代码, 灵活运用模式才是其根本, 别学死
板了。
我们继续看未成年超人的建造者, 如代码清单30-9所示。
代码清单30-9 未成年超人建造者
public class ChildSuperManBuilder extends Builder {
@Override
public SuperMan getSuperMan() {
super.setBody("强壮的躯体");
super.setSpecialTalent("刀枪不入");
super.setSpecialSymbol("胸前带小S标记");
return super.superMan;
}
}
大家注意看我们这两个具体的建造者, 它们都关注了产品的各个部分, 在某些应用场景
下甚至会关心产品的构建顺序, 即使是相同的部件, 装配顺序不同, 产生的结果也不同, 这
也正是建造者模式的意图: 通过不同的部件、 不同装配产生不同的复杂对象。 我们再来看导
演类, 如代码清单30-10所示。
代码清单30-10 导演类
public class Director {
//两个建造者的应用
private static Builder adultBuilder = new AdultSuperManBuilder();
//未成年超人的建造者
private static Builder childBuilder = new ChildSuperManBuilder();
//建造一个成年、 会飞行的超人
public static SuperMan getAdultSuperMan(){
return adultBuilder.getSuperMan();
}/
/建造一个未成年、 刀枪不入的超人
public static SuperMan getChildSuperMan(){
return childBuilder.getSuperMan();
}
}
这很简单, 不多说了! 看看场景类是如何调用的, 如代码清单30-11所示。代码清单30-11 场景类
public class Client {
public static void main(String[] args) {
//建造一个成年超人
SuperMan adultSuperMan = Director.getAdultSuperMan();
//展示一下超人的信息
adultSuperMan.getSpecialTalent();
}
}
这个场景类的写法与工厂方法模式是相同的, 但是你可以看到, 在建立超人的过程中,
建造者必须关注超人的各个部件, 而工厂方法模式则只关注超人的整体, 这就是两者的区
别。
30.1.3 最佳实践
工厂方法模式和建造者模式都属于对象创建类模式, 都用来创建类的对象。 但它们之间
的区别还是比较明显的。
● 意图不同
在工厂方法模式里, 我们关注的是一个产品整体, 如超人整体, 无须关心产品的各部分
是如何创建出来的; 但在建造者模式中, 一个具体产品的产生是依赖各个部件的产生以及装
配顺序, 它关注的是“由零件一步一步地组装出产品对象”。 简单地说, 工厂模式是一个对象
创建的粗线条应用, 建造者模式则是通过细线条勾勒出一个复杂对象, 关注的是产品组成部
分的创建过程。
● 产品的复杂度不同
工厂方法模式创建的产品一般都是单一性质产品, 如成年超人, 都是一个模样, 而建造
者模式创建的则是一个复合产品, 它由各个部件复合而成, 部件不同产品对象当然不同。 这
不是说工厂方法模式创建的对象简单, 而是指它们的粒度大小不同。 一般来说, 工厂方法模
式的对象粒度比较粗, 建造者模式的产品对象粒度比较细。两者的区别有了, 那在具体的应用中, 我们该如何选择呢? 是用工厂方法模式来创建对
象, 还是用建造者模式来创建对象, 这完全取决于我们在做系统设计时的意图, 如果需要详
细关注一个产品部件的生产、 安装步骤, 则选择建造者, 否则选择工厂方法模式。30.2 抽象工厂模式VS建造者模式
抽象工厂模式实现对产品家族的创建, 一个产品家族是这样的一系列产品: 具有不同分
类维度的产品组合, 采用抽象工厂模式则是不需要关心构建过程, 只关心什么产品由什么工
厂生产即可。 而建造者模式则是要求按照指定的蓝图建造产品, 它的主要目的是通过组装零
配件而产生一个新产品, 两者的区别还是比较明显的, 但是还有读者对这两个模式产生混
淆, 我们通过一个例子说明两者的差别。
现代化的汽车工厂能够批量生产汽车(不考虑手工打造的豪华车) 。 不同的工厂生产不
同的汽车, 宝马工厂生产宝马牌子的车, 奔驰工厂生产奔驰牌子的车。 车不仅具有不同品
牌, 还有不同的用途分类, 如商务车Van, 运动型车SUV等, 我们按照两种设计模式分别实
现车辆的生产过程。
30.2.1 按抽象工厂模式生产车辆
按照抽象工厂模式, 首先需要定义一个抽象的产品接口即汽车接口, 然后宝马和奔驰分
别实现该接口, 由于它们只具有了一个品牌属性, 还没有定义一个具体的型号, 属于对象的
抽象层次, 每个具体车型由其子类实现, 如R系列的奔驰车是商务车, X系列的宝马车属于
SUV, 我们来看类图, 如图30-3所示。图30-3 车辆生产的工厂类图
在类图中, 产品类很简单, 我们从两个维度看产品: 品牌和车型, 每个品牌下都有两个
车型, 如宝马SUV, 宝马商务车等, 同时我们又建造了两个工厂, 一个专门生产宝马车的宝
马工厂BMWFactory, 一个是生产奔驰车的奔驰车生产工厂BenzFactory。 当然, 汽车工厂也
有两个不同的维度, 可以建立这样两个工厂: 一个专门生产SUV车辆的生产工厂, 生产宝马
SUV和奔驰SUV, 另外一个工厂专门生成商务车, 分别是宝马商务车和奔驰商务车, 这样设
计在技术上是完全可行的, 但是在业务上是不可行的, 为什么? 这是因为你看到过有一个工
厂既能生产奔驰SUV也能生产宝马SUV吗? 这是不可能的, 因为业务受限, 除非是国内的山
寨工厂。 我们先来看产品类, 汽车接口如代码清单30-12所示。
代码清单30-12 汽车接口
public interface ICar {
//汽车的生产商, 也就是牌子
public String getBand();
//汽车的型号
public String getModel();
}
在产品接口中我们定义了车辆有两个可以查询的属性: 品牌和型号, 奔驰车和宝马车是
两个不同品牌的产品, 但不够具体, 只是知道它们的品牌而已, 还不能够实例化, 因此还是一个抽象类, 如代码清单30-13所示。
代码清单30-13 抽象宝马车
public abstract class AbsBMW implements ICar {
private final static String BMW_BAND = "宝马汽车";
//宝马车
public String getBand() {
return BMW_BAND;
}/
/型号由具体的实现类实现
public abstract String getModel();
}
抽象产品类中实现了产品的类型定义, 车辆的型号没有实现, 两实现类分别实现商务车
和运动型车, 分别如代码清单30-14、 代码清单30-15所示。
代码清单30-14 宝马商务车
public class BMWVan extends AbsBMW {
private final static String SEVENT_SEARIES = "7系列车型商务车";
public String getModel() {
return SEVENT_SEARIES;
}
}
代码清单30-15 宝马SUV
public class BMWSuv extends AbsBMW {
private final static String X_SEARIES = "X系列车型SUV";
public String getModel() {
return X_SEARIES;
}
}
奔驰车与宝马车类似, 都已经有清晰品牌定义, 但是型号还没有确认, 也是一个抽象的
产品类, 如代码清单30-16所示。
代码清单30-16 抽象奔驰车
public abstract class AbsBenz implements ICar {
private final static String BENZ_BAND = "奔驰汽车";
public String getBand() {
return BENZ_BAND;
}/
/具体型号由实现类完成public abstract String getModel();
}
由于分类的标准是相同的, 因此奔驰车也应该有商务车和运动车两个类型, 分别如代码
清单30-17和代码清单30-18所示。
代码清单30-17 奔驰商务车
public class BenzVan extends AbsBenz {
private final static String R_SERIES = "R系列商务车";
public String getModel() {
return R_SERIES;
}
}代
码清单30-18 奔驰SUV
public class BenzSuv extends AbsBenz {
private final static String G_SERIES = "G系列SUV";
public String getModel() {
return G_SERIES;
}
}
所有的产品类都已经实现了, 剩下的工作就是要定义工厂类进行生产, 由于产品类型多
样, 也导致了必须有多个工厂类来生产不同产品, 首先就需要定义一个抽象工厂, 声明每个
工厂必须完成的职责, 如代码清单30-19所示。
代码清单30-19 抽象工厂
public interface CarFactory {
//生产SUV
public ICar createSuv();
//生产商务车
public ICar createVan();
}
抽象工厂定义了每个工厂必须生产两个类型车: SUV(运动车) 和VAN(商务车) , 否
则一个工厂就不能被实例化, 我们来看宝马车工厂, 如代码清单30-20所示。
代码清单30-20 宝马车工厂
public class BMWFactory implements CarFactory {
//生产SUV
public ICar createSuv() {
return new BMWSuv();}/
/生产商务车
public ICar createVan(){
return new BMWVan();
}
}
很简单, 你要我生产宝马商务车, 没问题, 直接产生一个宝马商务车对象, 返回给调用
者, 这对调用者来说根本不需要关心到底是怎么生产的, 它只要找到一个宝马工厂, 即可生
产出自己需要的产品(汽车) 。 奔驰车工厂与此类似, 如代码清单30-21所示。
代码清单30-21 奔驰车工厂
public class BenzFactory implements CarFactory {
//生产SUV
public ICar createSuv() {
return new BenzSuv();
}/
/生产商务车
public ICar createVan(){
return new BenzVan();
}
}
产品和工厂都具备了, 剩下的工作就是建立一个场景类模拟调用者调用, 如代码清单
30-22所示。
代码清单30-22 场景类
public class Client {
public static void main(String[] args) {
//要求生产一辆奔驰SUV
System.out.println("===要求生产一辆奔驰SUV===");
//首先找到生产奔驰车的工厂
System.out.println("A、 找到奔驰车工厂");
CarFactory carFactory= new BenzFactory();
//开始生产奔驰SUV
System.out.println("B、 开始生产奔驰SUV");
ICar benzSuv = carFactory.createSuv();
//生产完毕, 展示一下车辆信息
System.out.println("C、 生产出的汽车如下: ");
System.out.println("汽车品牌: "+benzSuv.getBand());
System.out.println("汽车型号: " + benzSuv.getModel());
}
}
运行结果如下所示:===要求生产一辆奔驰SUV===
A、 找到奔驰车工厂
B、 开始生产奔驰SUV
C、 生产出的汽车如下:
汽车品牌: 奔驰汽车
汽车型号: G系列SUV
对外界调用者来说, 只要更换一个具备相同结构的对象, 即可发生非常大的改变, 如我
们原本使用BenzFactory生产汽车, 但是过了一段时间后, 我们的系统需要生产宝马汽车, 这
对系统来说不需要很大的改动, 只要把工厂类使用BMWFactory代替即可, 立刻可以生产出
宝马车, 注意这里生产的是一辆完整的车, 对于一个产品, 只要给出产品代码(车类型) 即
可生产, 抽象工厂模式把一辆车认为是一个完整的、 不可拆分的对象。 它注重完整性, 一个
产品一旦找到一个工厂生产, 那就是固定的型号, 不会出现一个宝马工厂生产奔驰车的情
况。 那现在的问题是我们就想要一辆混合的车型, 如奔驰的引擎, 宝马的车轮, 那该怎么处
理呢? 使用我们的建造者模式!
30.2.2 按建造者模式生产车辆
按照建造者模式设计一个生产车辆需要把车辆进行拆分, 拆分成引擎和车轮两部分, 然
后由建造者进行建造, 想要什么车, 你只要有设计图纸就成, 马上可以制造一辆车出来。 它
注重的是对零件的装配、 组合、 封装, 它从一个细微构件装配角度看待一个对象。 我们来看
生产车辆的类图, 如图30-4所示。
注意看我们类图中的蓝图类Blueprint, 它负责对产品建造过程定义。 既然要生产产品,
那必然要对产品进行一个描述, 在类图中我们定义了一个接口来描述汽车, 如代码清单30-
23所示。
代码清单30-23 车辆产品描述public interface ICar {
//汽车车轮
public String getWheel();
//汽车引擎
public String getEngine();
}
图30-4 建造者模式建造车辆
我们定义一辆车必须有车轮和引擎, 具体的产品如代码清单30-24所示。
代码清单30-24 具体车辆
public class Car implements ICar {
//汽车引擎
private String engine;
//汽车车轮
private String wheel;
//一次性传递汽车需要的信息
public Car(String _engine,String _wheel){
this.engine = _engine;
this.wheel = _wheel;
}p
ublic String getEngine() {
return engine;}p
ublic String getWheel() {
return wheel;
}p
ublic String toString(){
return "车的轮子是: " + wheel + " 车的引擎是: " + engine;
}
}
一个简单的JavaBean定义产品的属性, 明确对产品的描述。 我们继续来思考, 因为我们
的产品是比较抽象的, 它没有指定引擎的型号, 也没有指定车轮的牌子, 那么这样的组合方
式有很多, 完全要靠建造者来建造, 建造者说要生产一辆奔驰SUV那就得用奔驰的引擎和奔
驰的车轮, 该建造者对于一个具体的产品来说是绝对的权威, 我们来描述一下建造者, 如代
码清单30-25所示。
代码清单30-25 抽象建造者
public abstract class CarBuilder {
//待建造的汽车
private ICar car;
//设计蓝图
private Blueprint bp;
public Car buildCar(){
//按照顺序生产一辆车
return new Car(buildEngine(),buildWheel());
}/
/接收一份设计蓝图
public void receiveBlueprint(Blueprint _bp){
this.bp = _bp;
}/
/查看蓝图, 只有真正的建造者才可以查看蓝图
protected Blueprint getBlueprint(){
return bp;
}/
/建造车轮
protected abstract String buildWheel();
//建造引擎
protected abstract String buildEngine();
}
看到Blueprint类了, 它中文的意思是“蓝图”, 你要建造一辆车必须有一个设计样稿或者
蓝图吧, 否则怎么生产? 怎么装配? 该类就是一个可参考的生产样本, 如代码清单30-26所
示。
代码清单30-26 生产蓝图public class Blueprint {
//车轮的要求
private String wheel;
//引擎的要求
private String engine;
public String getWheel() {
return wheel;
}p
ublic void setWheel(String wheel) {
this.wheel = wheel;
}p
ublic String getEngine() {
return engine;
}p
ublic void setEngine(String engine) {
this.engine = engine;
}
}
这和一个具体的产品Car类是一样的? 错, 不一样! 它是一个蓝图, 是一个可以参考的
模板, 有一个蓝图可以设计出非常多的产品, 如有一个R系统的奔驰商务车设计蓝图, 我们
就可以生产出一系列的奔驰车。 它指导我们的产品生产, 而不是一个具体的产品。 我们来看
宝马车建造车间, 如代码清单30-27所示。
代码清单30-27 宝马车建造车间
public class BMWBuilder extends CarBuilder {
public String buildEngine() {
return super.getBlueprint().getEngine();
}p
ublic String buildWheel() {
return super.getBlueprint().getWheel();
}
}
这是非常简单的类。 只要获得一个蓝图, 然后按照蓝图制造引擎和车轮即可, 剩下的事
情就交给抽象的建造者进行装配。 奔驰车间与此类似, 如代码清单30-28所示。
代码清单30-28 奔驰车建造车间
public class BenzBuilder extends CarBuilder {
public String buildEngine() {
return super.getBlueprint().getEngine();
}p
ublic String buildWheel() {
return super.getBlueprint().getWheel();
}}
两个建造车间都已经完成, 那现在的问题就变成了怎么让车间运作, 谁来编写蓝图? 谁
来协调生产车间? 谁来对外提供最终产品? 于是导演类出场了, 它不仅仅有每个车间需要的
设计蓝图, 还具有指导不同车间装配顺序的职责, 如代码清单30-29所示。
代码清单30-29 导演类
public class Director {
//声明对建造者的引用
private CarBuilder benzBuilder = new BenzBuilder();
private CarBuilder bmwBuilder = new BMWBuilder();
//生产奔驰SUV
public ICar createBenzSuv(){
//制造出汽车
return createCar(benzBuilder, "benz的引擎", "benz的轮胎");
}/
/生产出一辆宝马商务车
public ICar createBMWVan(){
return createCar(benzBuilder, "BMW的引擎", "BMW的轮胎");
}/
/生产出一个混合车型
public ICar createComplexCar(){
return createCar(bmwBuilder, "BMW的引擎", "benz的轮胎");
}/
/生产车辆
private ICar createCar(CarBuilder _carBuilder,String engine,String wheel){
//导演怀揣蓝图
Blueprint bp = new Blueprint();
bp.setEngine(engine);
bp.setWheel(wheel);
System.out.println("获得生产蓝图");
_carBuilder.receiveBlueprint(bp);
return _carBuilder.buildCar();
}
}
这里有一个私有方法createCar, 其作用是减少导演类中的方法对蓝图的依赖, 全部由该
方法来完成。 我们编写一个场景类, 如代码清单30-30所示。
代码清单30-30 场景类
public class Client {
public static void main(String[] args) {
//定义出导演类
Director director =new Director();
//给我一辆奔驰车SUV
System.out.println("===制造一辆奔驰SUV===");ICar benzSuv = director.createBenzSuv();
System.out.println(benzSuv);
//给我一辆宝马商务车
System.out.println(" ===制造一辆宝马商务车===");
ICar bmwVan = director.createBMWVan();
System.out.println(bmwVan);
//给我一辆混合车型
System.out.println(" ===制造一辆混合车===");
ICar complexCar = director.createComplexCar();
System.out.println(complexCar);
}
}
场景类只要找到导演类(也就是车间主任了) 说给我制造一辆这样的宝马车, 车间主任
马上通晓你的意图, 设计了一个蓝图, 然后命令建造车间拼命加班加点建造, 最终返回给你
一件最新出品的产品, 运行结果如下所示:
===制造一辆奔驰SUV===
获得生产蓝图
车的轮子是: benz的轮胎
车的引擎是: benz的引擎
===制造一辆宝马商务车===
获得生产蓝图
车的轮子是: BMW的轮胎
车的引擎是: BMW的引擎
===制造一辆混合车===
获得生产蓝图
车的轮子是: benz的轮胎
车的引擎是: BMW的引擎
注意最后一个运行结果片段, 我们可以立刻生产出一辆混合车型, 只要有设计蓝图, 这
非常容易实现。 反观我们的抽象工厂模式, 它是不可能实现该功能的, 因为它更关注的是整
体, 而不关注到底用的是奔驰引擎还是宝马引擎, 而我们的建造者模式却可以很容易地实现
该设计, 市场信息变更了, 我们就可以立刻跟进, 生产出客户需要的产品。30.2.3 最佳实践
注意看上面的描述, 我们在抽象工厂模式中使用“工厂”来描述构建者, 而在建造者模式
中使用“车间”来描述构建者, 其实我们已经在说它们两者的区别了, 抽象工厂模式就好比是
一个一个的工厂, 宝马车工厂生产宝马SUV和宝马VAN, 奔驰车工厂生产奔驰车SUV和奔驰
VAN, 它是从一个更高层次去看对象的构建, 具体到工厂内部还有很多的车间, 如制造引擎
的车间、 装配引擎的车间等, 但这些都是隐藏在工厂内部的细节, 对外不公布。 也就是对领
导者来说, 他只要关心一个工厂到底是生产什么产品的, 不用关心具体怎么生产。 而建造者
模式就不同了, 它是由车间组成, 不同的车间完成不同的创建和装配任务, 一个完整的汽车
生产过程需要引擎制造车间、 引擎装配车间的配合才能完成, 它们配合的基础就是设计蓝
图, 而这个蓝图是掌握在车间主任(导演类) 手中, 它给建造车间什么蓝图就能生产什么产
品, 建造者模式更关心建造过程。 虽然从外界看来一个车间还是生产车辆, 但是这个车间的
转型是非常快的, 只要重新设计一个蓝图, 即可产生不同的产品, 这有赖于建造者模式的功
劳。
相对来说, 抽象工厂模式比建造者模式的尺度要大, 它关注产品整体, 而建造者模式关
注构建过程, 因此建造者模式可以很容易地构建出一个崭新的产品, 只要导演类能够提供具
体的工艺流程。 也正因为如此, 两者的应用场景截然不同, 如果希望屏蔽对象的创建过程,
只提供一个封装良好的对象, 则可以选择抽象工厂方法模式。 而建造者模式可以用在构件的
装配方面, 如通过装配不同的组件或者相同组件的不同顺序, 可以产生出一个新的对象, 它
可以产生一个非常灵活的架构, 方便地扩展和维护系统。

以上是关于创建类模式大PK的主要内容,如果未能解决你的问题,请参考以下文章

设计模式之行为类模式大PK

《设计模式之禅》--设计模式大PK

设计模式之创建类模式PK

设计模式 模式PK:装饰模式VS适配器模式

设计模式之行为类模式PK

设计模式 模式PK:策略模式VS状态模式