没有人买车会只买一个轮胎或者方向盘,大家买的都是一辆包含轮胎、方向盘和发动机等多 个部件的完整汽车。如何将这些部件组装成一辆完整的汽车并返回给用户,这是建造者模式 需要解决的问题。建造者模式又称为生成器模式,它是一种较为复杂、使用频率也相对较低 的创建型模式。建造者模式为客户端返回的不是一个简单的产品,而是一个由多个部件组成 的复杂产品。
软件公司游戏开发小组决定开发一款名为《Sunny群侠传》的网络游戏,该游戏采用主 流的RPG(Role Playing Game,角色扮演游戏)模式,玩家可以在游戏中扮演虚拟世界中的一个特 定角色,角色根据不同的游戏情节和统计数据(如力量、魔法、技能等)具有不同的能力, 角色也会随着不断升级而拥有更加强大的能力。 作为RPG游戏的一个重要组成部分,需要对游戏角色进行设计,而且随着该游戏的升级将不 断增加新的角色。不同类型的游戏角色,其性别、脸型、服装、发型等外部特性都有所差 异,例如“天使”拥有美丽的面容和披肩的长发,并身穿一袭白裙;而“恶魔”极其丑陋,留着光 头并穿一件刺眼的黑衣。 Sunny公司决定开发一个小工具来创建游戏角色,可以创建不同类型 的角色并可以灵活增加新的角色。 公司的开发人员通过分析发现,游戏角色是一个复杂对象,它包含性别、脸型等多个组 成部分,不同的游戏角色其组成部分有所差异
无论是何种造型的游戏角色,它的创建步骤都大同小异,都需要逐步创建其组成部分,再将 各组成部分装配成一个完整的游戏角色。如何一步步创建一个包含多个组成部分的复杂对 象,建造者模式为解决此类问题而诞生。
建造者模式是较为复杂的创建型模式,它将客户端与包含多个组成部分(或部件)的复杂对 象的创建过程分离,客户端无须知道复杂对象的内部组成部分与装配方式,只需要知道所需 建造者的类型即可。它关注如何一步一步创建一个的复杂对象,不同的具体建造者定义了不 同的创建过程,且具体建造者相互独立,增加新的建造者非常方便,无须修改已有代码,系统具有较好的扩展性。 建造者模式定义如下: 建造者模式(Builder Pattern):将一个复杂对象的构建与它的表示分离,使得同样的构建过程可 以创建不同的表示。建造者模式是一种对象创建型模式。
建造者模式一步一步创建一个复杂的对象,它允许用户只通过指定复杂对象的类型和内容就 可以构建它们,用户不需要知道内部的具体构建细节。
在建造者模式结构图中包含如下几个角色:
● Builder(抽象建造者):它为创建一个产品Product对象的各个部件指定抽象接口,在该接 口中一般声明两类方法,一类方法是buildPartX(),它们用于创建复杂对象的各个部件;另一 类方法是getResult(),它们用于返回复杂对象。Builder既可以是抽象类,也可以是接口。
●ConcreteBuilder(具体建造者):它实现了Builder接口,实现各个部件的具体构造和装配方 法,定义并明确它所创建的复杂对象,也可以提供一个方法返回创建好的复杂产品对象。
●Product(产品角色):它是被构建的复杂对象,包含多个组成部件,具体建造者创建该产品 的内部表示并定义它的装配过程。
● Director(指挥者):指挥者又称为导演类,它负责安排复杂对象的建造次序,指挥者与抽 象建造者之间存在关联关系,可以在其construct()建造方法中调用建造者对象的部件构造与装 配方法,完成复杂对象的建造。客户端一般只需要与指挥者进行交互,在客户端确定具体建 造者的类型,并实例化具体建造者对象(也可以通过配置文件和反射机制),然后通过指挥 者类的构造函数或者Setter方法将该对象传入指挥者类中。
举个栗子:
我们用制造自行车为例子讲解建造者模式,自行车由车架、轮胎、脚踏等部件组成,如下图所示。自行车制造公司就是把这些零部件组装起来。
自行车制造公司的工程部门相当于指挥者,生产部门相当于建造者,当今共享单车做的比较大的摩拜和ofo相当于客户,单车就是产品了。
一起来看看如何用代码来实现
1、定义创建者接口,也就是生产线接口
package com.jet.pattern.builder; import com.jet.pattern.builder.impl.Bike; /** * description: * 自行车生产线接口 * Created by chenzanjin on 2017/2/22. */ public interface BikeBuilder { // 组装轮胎 public void buildTyres(); // 组装车架 public void buildFrame(); // 组装GPS定位装置 public void buildGPS(); // 获取自行车 public Bike getBike(); } |
package com.jet.pattern.builder.impl; import com.jet.pattern.builder.BikeBuilder; /** * description: * 摩拜单车生产线 * Created by chenzanjin on 2017/2/22. */ public 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; } } |
3、定义ofo单车生产线
package com.jet.pattern.builder.impl; import com.jet.pattern.builder.BikeBuilder; /** * description: * ofo单车生产线 * Created by chenzanjin on 2017/2/22. */ public 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; } } |
package com.jet.pattern.builder.impl; /** * description: * 自行车对象 * Created by chenzanjin on 2017/2/22. */ public class Bike { // 轮胎 private String tyre; // 车架 private String frame; // GPS定位装置 private String gps; public String getTyre() { return tyre; } public void setTyre(String tyre) { this.tyre = tyre; } public String getFrame() { return frame; } public void setFrame(String frame) { this.frame = frame; } public String getGps() { return gps; } public void setGps(String gps) { this.gps = gps; } } |
package com.jet.pattern.builder.impl; import com.jet.pattern.builder.BikeBuilder; /** * description: * 工程部门作为指挥者,可以指导生产部门作业 * Created by Administrator on 2017/2/22. */ public class EngineeringDepartment { // 用户告知指挥者想要什么样的单车 BikeBuilder bikeBuilder; public EngineeringDepartment(BikeBuilder bikeBuilder) { this.bikeBuilder = bikeBuilder; } // 指导组装单车 public void Construct() { bikeBuilder.buildTyres(); bikeBuilder.buildFrame(); bikeBuilder.buildGPS(); } } |
6、测试类
package com.jet.pattern.builder.impl; import com.jet.pattern.builder.BikeBuilder; /** * description: * 建造者测试类 * Created by Administrator on 2017/2/22. */ public 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(); } } |
建造者模式的核心在于如何一步步构建一个包含多个组成部件的完整对象,使用相同的构建 过程构建不同的产品,在软件开发中,如果我们需要创建复杂对象并希望系统具备很好的灵 活性和可扩展性可以考虑使用建造者模式。
1.主要优点
建造者模式的主要优点如下:
(1) 在建造者模式中,客户端不必知道产品内部组成的细节,将产品本身与产品的创建过程解 耦,使得相同的创建过程可以创建不同的产品对象。
(2) 每一个具体建造者都相对独立,而与其他的具体建造者无关,因此可以很方便地替换具体 建造者或增加新的具体建造者,用户使用不同的具体建造者即可得到不同的产品对象。由于 指挥者类针对抽象建造者编程,增加新的具体建造者无须修改原有类库的代码,系统扩展方 便,符合“开闭原则”
(3) 可以更加精细地控制产品的创建过程。将复杂产品的创建步骤分解在不同的方法中,使得 创建过程更加清晰,也更方便使用程序来控制创建过程。
2.主要缺点
建造者模式的主要缺点如下:
(1) 建造者模式所创建的产品一般具有较多的共同点,其组成部分相似,如果产品之间的差异 性很大,例如很多组成部分都不相同,不适合使用建造者模式,因此其使用范围受到一定的 限制。
(2) 如果产品的内部变化复杂,可能会导致需要定义很多具体建造者类来实现这种变化,导致 系统变得很庞大,增加系统的理解难度和运行成本。
3.适用场景
在以下情况下可以考虑使用建造者模式:
(1) 需要生成的产品对象有复杂的内部结构,这些产品对象通常包含多个成员属性。
(2) 需要生成的产品对象的属性相互依赖,需要指定其生成顺序。
(3) 对象的创建过程独立于创建该对象的类。在建造者模式中通过引入了指挥者类,将创建过 程封装在指挥者类中,而不在建造者类和客户类中。
(4) 隔离复杂对象的创建和使用,并使得相同的创建过程可以创建不同的产品。