设计模式(四)-----建造者模式(Builder Pattern)

建造者模式是一种创建型设计模式,用于分步骤构建复杂的对象。它将产品对象的创建过程与使用分离,允许同构产品的构建有不同的实现。文章通过代码示例展示了如何使用建造者模式创建电子杂志系统的欢迎和欢送邮件,同时对比了建造者模式与抽象工厂模式的区别。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

墨菲定律中提到:任何事都没有表面看起来的那么简单。无论在现实生活中还是在代码世界中,都存在一些复杂的对象,他们由多个部分组成,每个部分各具功能,协同运作。比如手机包含摄像头、CPU、电池等各种零部件。对于大部分用户而言,无须知道部件之间的组装细节,也几乎不会单独使用某个零部件,而是使用一部完整的手机。如果需要详细关注一个产品部件的生产、安装步骤,可以选择建造者模式对其进行设计与描述,将部件和其组装过程分开,分步创建一个复杂的对象。由于组装部件的过程复杂,因此,装配过程被分离到一个称作建造者的对象里,建造者返回给上层一个完整产品,而无须关心该产品的构建细节,这就是建造者模式的核心思想。

什么是建造者模式

建造者模式将复杂产品的创建步骤分解在在不同的方法中,使得创建过程更加清晰,从而更精确控制复杂对象的产生过程;通过隔离复杂对象的构建与使用,也就是将产品的创建与产品本身分离开来,使得同样的构建过程可以创建不同的对象;并且每个具体建造者都相互独立,因此可以很方便地替换具体建造者或增加新的具体建造者,用户使用不同的具体建造者即可得到不同的产品对象。

一般建造者模式都有以下几种固定的角色:

抽象建造者(Builder)角色:给 出一个抽象接口,以规范产品对象的各个组成成分的建造。一般而言,此接口独立于应用程序的商业逻辑。模式中直接创建产品对象的是具体建造者 (ConcreteBuilder)角色。具体建造者类必须实现这个接口所要求的两种方法:一种是建造方法(buildPart1和 buildPart2),另一种是返还结构方法(retrieveResult)。一般来说,产品所包含的零件数目与建造方法的数目相符。换言之,有多少 零件,就有多少相应的建造方法。

具体建造者(ConcreteBuilder)角色:担任这个角色的是与应用程序紧密相关的一些类,它们在应用程序调用下创建产品的实例。这个角色要完成的任务包括:1.实现抽象建造者Builder所声明的接口,给出一步一步地完成创建产品实例的操作。2.在建造过程完成后,提供产品的实例。

导演者(Director)角色:担任这个角色的类调用具体建造者角色以创建产品对象。应当指出的是,导演者角色并没有产品类的具体知识,真正拥有产品类的具体知识的是具体建造者角色。

产品(Product)角色:产品便是建造中的复杂对象。一般来说,一个系统中会有多于一个的产品类,而且这些产品类并不一定有共同的接口,而完全可以是不相关联的。

用途

  1. 需要生成的产品对象有复杂的内部结构,每一个内部成分本身可以是对象,也可以仅仅是一个对象(即产品对象)的一个组成部分。
  2. 需要生成的产品对象的属性相互依赖。建造模式可以强制实行一种分步骤进行的建造过程,因此,如果产品对象的一个属性必须在另一个属性被赋值之后才可以被赋值,使用建造模式是一个很好的设计思想。
  3. 在对象创建过程中会使用到系统中的其他一些对象,这些对象在产品对象的创建过程中不易得到

代码实现

假设有一个电子杂志系统,定期地向用户的电子邮件信箱发送电子杂志。用户可以通过网页订阅电子杂志,也可以通过网页结束订阅。当客户开始订阅时,系统发送一个电子邮件表示欢迎,当客户结束订阅时,系统发送一个电子邮件表示欢送。本例子就是这个系统负责发送“欢迎”和“欢送”邮件的模块。

这个系统含有客户端(Client)、导演者(Director)、抽象建造者(Builder)、具体建造者(WelcomeBuilder和GoodbyeBuilder)、产品(WelcomeMessage和GoodbyeMessage)等角色。

完整代码路径

抽象类AutoMessage源代码

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() {
        msg.setBody("欢迎内容");
    }

    @Override
    public void buildSubject() {
        msg.setSubject("欢迎标题");
    }
}

具体建造者GoodbyeBuilder

public class GoodbyeBuilder extends Builder{
    public GoodbyeBuilder(){
        msg = new GoodbyeMessage();
    }
    @Override
    public void buildBody() {
        msg.setBody("欢送内容");
    }

    @Override
    public void buildSubject() {
        msg.setSubject("欢送标题");
    }
}

导演者Director,这个类提供一个construct()方法,此方法调用建造者的建造方法,包括buildTo()、buildFrom()、buildSubject()、buildBody()、buildSendDate()等,从而一部分一部分地建造出产品对象,既AutoMessage对象。

public class Director {
    public 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) {
        Builder builder = new WelcomeBuilder();
        Director director = new Director(builder);
        director.construct("saasa","assa");
    }
}

运行结果
在这里插入图片描述

建造模式分成两个很重要的部分:

  1. 一个部分是Builder接口,这里是定义了如何构建各个部件,也就是知道每个部件功能如何实现,以及如何装配这些部件到产品中去;
  2. 另外一个部分是Director,Director是知道如何组合来构建产品,也就是说Director负责整体的构建算法,而且通常是分步骤地来执行。

不管如何变化,建造模式都存在这么两个部分,一个部分是部件构造和产品装配另一个部分是整体构建的算法。认识这点是很重要的,因为在建造模式中,强调的是固定整体构建的算法,而灵活扩展和切换部件的具体构造和产品装配的方式。

再直白点说,建造模式的重心在于分离构建算法和具体的构造实现,从而使得构建算法可以重用。具体的构造实现可以很方便地扩展和切换,从而可以灵活地组合来构造出不同的产品对象。

抽象工厂模式和建造者模式的区别:

    两者都是创建型模式,并且最终都是得到一个产品,但两者的区别在于:
  1. 抽象工厂模式实现对产品族的创建,产品族指的是不同分类维度的产品组合,用抽象工厂模式不需要关心具体构建过程,只关心产品由什么工厂生产即可。而建造者模式则更关心的是对象的构建过程,要求按照指定的蓝图建造产品,主要目的是通过组装零配件而产生一个新产品。

  2. 在抽象工厂模式中使用“工厂”来描述构建者,而在建造者模式中使用“车间”来描述构建者。
    (1)抽象工厂模式就好比是一个一个的工厂,宝马车工厂生产宝马SUV和宝马VAN,奔驰车工厂生产奔驰车SUV和奔驰VAN,它是从一个更高层次去看对象的构建,具体到工厂内部还有很多的车间,如制造引擎的车间、装配引擎的车间等,但这些都是隐藏在工厂内部的细节,对外不公布。也就是对领导者来说,他只要关心一个工厂到底是生产什么产品的,不用关心具体怎么生产。
    (2)建造者模式就不同了,它是由车间组成,不同的车间完成不同的创建和装配任务,一个完整的汽车生产过程需要引擎制造车间、引擎装配车间的配合才能完成,它们配合的基础就是设计蓝图,而这个蓝图是掌握在车间主任(Director类)手中,它给建造车间什么蓝图就能生产什么产品,建造者模式更关心建造过程。虽然从外界看来一个车间还是生产车辆,但是这个车间的转型是非常快的,只要重新设计一个蓝图,即可产生不同的产品,这有赖于建造者模式的功劳。

  3. 相对来说,抽象工厂模式比建造者模式的粒度要大,它关注产品整体,而建造者模式关注构建过程,所以建造者模式可以很容易地构建出一个崭新的产品,只要指挥类 Director 能够提供具体的工艺流程。也正因为如此,两者的应用场景截然不同,如果希望屏蔽对象的创建过程,只提供一个封装良好的对象,则可以选择抽象工厂方法模式。而建造者模式可以用在构件的装配方面,如通过装配不同的组件或者相同组件的不同顺序,可以产生出一个新的对象,它可以产生一个非常灵活的架构,方便地扩展和维护系统。

参考文件:

https://blog.youkuaiyun.com/a745233700/article/details/83625236
https://blog.youkuaiyun.com/Small_Mouse0/article/details/66474580

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值