主页传送门:💁 传送
1.建造者模式定义
建造者模式(Builder Pattern)也叫做生成器模式,是一种常用的设计模式。其定义如下:
Separate the construction of a complex object from its representation so that the same construction process can create different representations.
即:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
建造者模式的通用类图如下:
2.建造者模式的角色
在建造者模式中有如下4个角色:
- 产品(Product)类
产品便是建造中的复杂对象。一般来说,一个系统中会有多于一个的产品类,而且这些产品类并不一定有共同的接口,而完全可以是不相关联的。 - 抽象建造者(Builder)
给出一个抽象接口,以规范产品对象的各个组成成分的建造。一般而言,此接口独立于应用程序的商业逻辑。模式中直接创建产品对象的是具体建造者 (ConcreteBuilder)角色。具体建造者类必须实现这个接口所要求的两种方法:一种是建造方法(buildPart1),另一种是返还结构方法(retrieveResult)。一般来说,产品所包含的零件数目与建造方法的数目相符。换言之,有多少 零件,就有多少相应的建造方法。 - 具体建造者(ConcreteBuilder)
担任这个角色的是与应用程序紧密相关的一些类,它们在应用程序调用下创建产品的实例。这个角色要完成的任务包括:1.实现抽象建造者Builder所声明的接口,给出一步一步地完成创建产品实例的操作。2.在建造过程完成后,提供产品的实例。 - 导演者(Director)
担任这个角色的类调用具体建造者角色以创建产品对象。应当指出的是,导演者角色并没有产品类的具体知识,真正拥有产品类的具体知识的是具体建造者角色。
导演者角色是与客户端打交道的角色。导演者将客户端创建产品的请求划分为对各个零件的建造请求,再将这些请求委派给具体建造者角色。具体建造者角色是做具体建造工作的,但是却不为客户端所知。
一般来说,每有一个产品类,就有一个相应的具体建造者类。这些产品应当有一样数目的零件,而每有一个零件就相应地在所有的建造者角色里有一个建造方法。
3.建造者模式实战案例
3.1.场景说明
假设有一个电子杂志系统,定期地向用户的电子邮件信箱发送电子杂志。用户可以通过网页订阅电子杂志,也可以通过网页结束订阅。当客户开始订阅时,系统发送一个电子邮件表示欢迎,当客户结束订阅时,系统发送一个电子邮件表示欢送。本例子就是这个系统负责发送“欢迎”和“欢送”邮件的模块。
3.2.关系类图
在本例中,产品类就是发给某个客户的“欢迎”和“欢送”邮件,如下图所示。
虽然在这个例子里面各个产品类均有一个共同的接口,但这仅仅是本例子特有的,并不代表建造模式的特点。建造模式可以应用到具有完全不同接口的产品类上。大多数情况下是不知道最终构建出来的产品是什么样的,所以在标准的建造模式里面,一般是不需要对产品定义抽象接口的,因为最终构造的产品千差万别,给这些产品定义公共接口几乎是没有意义的。
下图所示就是这个系统的类图。
这个系统含有客户端(Client)、导演者(Director)、抽象建造者(Builder)、具体建造者(WelcomeBuilder和GoodbyeBuilder)、产品(WelcomeMessage和GoodbyeMessage)等角色。
3.3.代码实现
抽象类AutoMessage源代码,send()操作仅仅是示意性的,并没有给出任何发送电子邮件的代码。
public abstract class AutoMessage {
//收件人地址
private String to;
//发件人地址
private String from;
//标题
private String subject;
//内容
private String body;
//发送日期
private Date sendDate;
public void send(){
System.out.println("收件人地址:" + to);
System.out.println("发件人地址:" + from);
System.out.println("标题:" + subject);
System.out.println("内容:" + body);
System.out.println("发送日期:" + sendDate);
}
public String getTo() {
return to;
}
public void setTo(String to) {
this.to = to;
}
public String getFrom() {
return from;
}
public void setFrom(String from) {
this.from = from;
}
public String getSubject() {
return subject;
}
public void setSubject(String subject) {
this.subject = subject;
}
public String getBody() {
return body;
}
public void setBody(String body) {
this.body = body;
}
public Date getSendDate() {
return sendDate;
}
public void setSendDate(Date sendDate) {
this.sendDate = sendDate;
}
}
具体产品类WelcomeMessage
public class WelcomeMessage extends AutoMessage {
/**
* 构造子
*/
public WelcomeMessage(){
System.out.println("发送欢迎信息");
}
}
具体产品类GoodbyeMessage
public class GoodbyeMessage extends AutoMessage{
/**
* 构造子
*/
public GoodbyeMessage(){
System.out.println("发送欢送信息");
}
}
抽象建造者类
public abstract class Builder {
protected AutoMessage msg;
//标题零件的建造方法
public abstract void buildSubject();
//内容零件的建造方法
public abstract void buildBody();
//收件人零件的建造方法
public void buildTo(String to){
msg.setTo(to);
}
//发件人零件的建造方法
public void buildFrom(String from){
msg.setFrom(from);
}
//发送时间零件的建造方法
public void buildSendDate(){
msg.setSendDate(new Date());
}
/**
* 邮件产品完成后,用此方法发送邮件
* 此方法相当于产品返还方法
*/
public void sendMessage(){
msg.send();
}
}
具体建造者WelcomeBuilder
public class WelcomeBuilder extends Builder {
public WelcomeBuilder(){
msg = new WelcomeMessage();
}
@Override
public void buildBody() {
// TODO Auto-generated method stub
msg.setBody("欢迎内容");
}
@Override
public void buildSubject() {
// TODO Auto-generated method stub
msg.setSubject("欢迎标题");
}
}
具体建造者GoodbyeBuilder
public class GoodbyeBuilder extends Builder {
public GoodbyeBuilder(){
msg = new GoodbyeMessage();
}
@Override
public void buildBody() {
// TODO Auto-generated method stub
msg.setBody("欢送内容");
}
@Override
public void buildSubject() {
// TODO Auto-generated method stub
msg.setSubject("欢送标题");
}
}
导演者Director,这个类提供一个construct()方法,此方法调用建造者的建造方法,包括buildTo()、buildFrom()、buildSubject()、buildBody()、buildSendDate()等,从而一部分一部分地建造出产品对象,既AutoMessage对象。
public class Director {
Builder builder;
/**
* 构造子
*/
public Director(Builder builder){
this.builder = builder;
}
/**
* 产品构造方法,负责调用各零件的建造方法
*/
public void construct(String toAddress , String fromAddress){
this.builder.buildTo(toAddress);
this.builder.buildFrom(fromAddress);
this.builder.buildSubject();
this.builder.buildBody();
this.builder.buildSendDate();
this.builder.sendMessage();
}
}
客户端Client
public class Client {
public static void main(String[] args) {
// TODO Auto-generated method stub
Builder builder = new WelcomeBuilder();
Director director = new Director(builder);
director.construct("toAddress@126.com", "fromAddress@126.com");
}
}
4.建造者模式优缺点
建造者模式的优点包括:
- 封装性好,构建和表示分离。
- 扩展性好,各个具体的建造者相互独立,有利于系统的解耦。
- 客户端不必知道产品内部组成的细节,建造者可以对创建过程逐步细化,而不对其它模块产生任何影响,便于控制细节风险。
然而,建造者模式也存在一些缺点:
- 产品的组成部分必须相同,这限制了其使用范围。
- 如果产品的内部变化复杂,如果产品内部发生变化,则建造者也要同步修改,后期维护成本较大。
5.建造者模式使用场景
建造者模式的使用场景包括但不限于以下情况:
- 需要生成的产品对象有复杂的内部结构,每一个内部成分本身可以是对象,也可以仅仅是一个对象(即产品对象)的一个组成部分。
- 需要生成的产品对象的属性相互依赖。建造模式可以强制实行一种分步骤进行的建造过程,因此,如果产品对象的一个属性必须在另一个属性被赋值之后才可以被赋值,使用建造模式是一个很好的设计思想。
- 在对象创建过程中会使用到系统中的其他一些对象,这些对象在产品对象的创建过程中不易得到。
6.建造者模式总结
建造者模式核心思想是将复杂对象的建造过程和表示分离,使用专门的类(Director)控制复杂对象的建造过程,结合里氏替换思想,使程序更支持开闭原则。
设计模式的学习一定要结合7大软件设计原则的核心思想进行理解,明白各个设计模式用到了什么思想或方法才满足相应的设计原则。
如果喜欢的话,欢迎 🤞关注 👍点赞 💬评论 🤝收藏 🙌一起讨论
你的支持就是我✍️创作的动力! 💞💞💞