设计模式-建造者模式在Java中使用示例

场景

建造者模式

复杂对象的组装与创建

没有人买车会只买一个轮胎或者方向盘,大家买的都是一辆包含轮胎、方向盘和发动机等多个部件的完整汽车。

如何将这些部件组装成一辆完整的汽车并返回给用户,这是建造者模式需要解决的问题。

建造者模式又称为生成器模式,它是一种较为复杂、使用频率也相对较低的创建型模式。

建造者模式为客户端返回的不是一个简单的产品,而是一个由多个部件组成的复杂产品。

建造者模式是较为复杂的创建型模式,它将客户端与包含多个组成部分(或部件)的复杂对象的创建过程分离,

客户端无须知道复杂对象的内部组成部分与装配方式,只需要知道所需建造者的类型即可。

它关注如何一步一步创建一个的复杂对象,不同的具体建造者定义了不同的创建过程,

且具体建造者相互独立,增加新的建造者非常方便,无须修改已有代码,系统具有较好的扩展性。

建造者模式举例

以角色扮演类游戏为例,需要对游戏角色进行设计,而且随着该游戏的升级将不断增加新的角色。

不同类型的游戏角色,其性别、脸型、服装等外部特性都有所差异。

开发一个小工具来创建游戏角色,可以创建不同类型的角色并可以灵活增加新的角色。

游戏角色是一个复杂对象,它包含性别、脸型等多个组成部分,不同的游戏角色其组成部分有所差异。

无论是何种造型的游戏角色,它的创建步骤都大同小异,都需要逐步创建其组成部分,

再将各组成部分装配成一个完整的游戏角色。如何一步步创建一个包含多个组成部分的复杂对象,

建造者模式为解决此类问题而诞生。

建造者模式结构图与角色

设计模式-建造者模式在Java中使用示例_第1张图片

建造者模式中包含如下角色

Builder(抽象建造者):
它为创建一个产品Product对象的各个部件指定抽象接口,在该接口中一般声明两类方法,
一类方法是buildPartX(),它们用于创建复杂对象的各个部件;
另一类方法是getResult(),它们用于返回复杂对象。
Builder既可以是抽象类,也可以是接口。

ConcreteBuilder(具体建造者):
它实现了Builder接口,实现各个部件的具体构造和装配方法,定义并明确它所创建的复杂对象,
也可以提供一个方法返回创建好的复杂产品对象。
在ConcreteBuilder中实现了buildPartX()方法,通过调用Product的setPartX()方法可以给产品对象的成员属性设值。
不同的具体建造者在实现buildPartX()方法时将有所区别,如setPartX()方法的参数可能不一样,
在有些具体建造者类中某些setPartX()方法无须实现(提供一个空实现)。
而这些对于客户端来说都无须关心,客户端只需知道具体建造者类型即可。

Product(产品角色):
它是被构建的复杂对象,包含多个组成部件,具体建造者创建该产品的内部表示并定义它的装配过程。
复杂对象是指那些包含多个成员属性的对象,这些成员属性也称为部件或零件,如汽车包括方向盘、发动机、轮胎等部件,
电子邮件包括发件人、收件人、主题、内容、附件等部件

Director(指挥者):
指挥者又称为导演类,它负责安排复杂对象的建造次序,指挥者与抽象建造者之间存在关联关系,
可以在其construct()建造方法中调用建造者对象的部件构造与装配方法,完成复杂对象的建造。
客户端一般只需要与指挥者进行交互,在客户端确定具体建造者的类型,并实例化具体建造者对象(也可以通过配置文件和反射机制),
然后通过指挥者类的构造函数或者Setter方法将该对象传入指挥者类中。
该类主要有两个作用:
一方面它隔离了客户与创建过程;
另一方面它控制产品的创建过程,包括某个buildPartX()方法是否被调用以及多个buildPartX()方法调用的先后次序等。
指挥者针对抽象建造者编程,客户端只需要知道具体建造者的类型,即可通过指挥者类调用建造者的相关方法,返回一个完整的产品对象。
在实际生活中也存在类似指挥者一样的角色,如一个客户去购买电脑,电脑销售人员相当于指挥者,只要客户确定电脑的类型,
电脑销售人员可以通知电脑组装人员给客户组装一台电脑。

建造者模式与工厂模式有何区别?

建造者模式与抽象工厂模式有点相似,但是建造者模式返回一个完整的复杂产品,而抽象工厂模式返回一系列相关的产品;
在抽象工厂模式中,客户端通过选择具体工厂来生成所需对象,而在建造者模式中,
客户端通过指定具体建造者类型并指导Director类如何去生成对象,侧重于一步步构造一个复杂对象,然后将结果返回。
如果将抽象工厂模式看成一个汽车配件生产厂,生成不同类型的汽车配件,那么建造者模式就是一个汽车组装厂,通过对配件进行组装返回一辆完整的汽车。

设计模式-简单工厂模式、工厂模式、抽象工厂模式在Java中的使用示例:

设计模式-简单工厂模式、工厂模式、抽象工厂模式在Java中的使用示例_java工厂模式应用场景举例_霸道流氓气质的博客-CSDN博客

注:

博客:
霸道流氓气质的博客_CSDN博客-C#,架构之路,SpringBoot领域博主

实现

下面使用建造者模式实现上面角色设计的流程

1、新建Actor充当复杂产品,这里使用lombok省略get和set方法。

import lombok.Data;

/**
 * 充当复杂产品
 */
@Data
public class Actor {
    //角色类型
    private String type;
    //性别
    private String sex;
    //脸型
    private String face;
    //服装
    private String costume;
}

2、新建抽象构造者ActorBuilder,并新增方法,返回一个完整的游戏角色对象

/**
 * 抽象构造者
 */
public abstract class ActorBuilder {

    protected Actor actor = new Actor();

    public abstract void buildType();
    public abstract void buildSex();
    public abstract void buildFace();
    public abstract void buildContume();

    //工厂方法,返回一个完整的游戏角色对象
    public Actor createActor(){
        return actor;
    }
}

3、具体建造者一共有三种角色:英雄、天使、恶魔

英雄角色构造器实现

/**
 * 英雄角色建造器:具体建造者
 */
public class HeroBuilder extends ActorBuilder {

    @Override
    public void buildType() {
        actor.setType("英雄");
    }

    @Override
    public void buildSex() {
        actor.setSex("男");
    }

    @Override
    public void buildFace() {
        actor.setFace("帅气");
    }

    @Override
    public void buildContume() {
        actor.setCostume("盔甲");
    }
}

天使角色构造器实现

/**
 * 天使角色建造器:具体建造者
 */
public class AngelBuilder extends ActorBuilder{
    @Override
    public void buildType() {
        actor.setType("天使");
    }

    @Override
    public void buildSex() {
        actor.setSex("女");
    }

    @Override
    public void buildFace() {
        actor.setFace("漂亮");
    }

    @Override
    public void buildContume() {
        actor.setCostume("翅膀");
    }
}

恶魔角色构造器实现

/**
 * 恶魔角色建造器:具体建造者
 */
public class DeviBuilder extends ActorBuilder
{
    @Override
    public void buildType() {
        actor.setType("恶魔");
    }

    @Override
    public void buildSex() {
        actor.setSex("男");
    }

    @Override
    public void buildFace() {
        actor.setFace("吓人");
    }

    @Override
    public void buildContume() {
        actor.setCostume("皮衣");
    }
}

4、新建指挥者-角色创建控制器

/**
 * 角色创建控制器:指挥者
 */
public class ActorController{

    //逐步构建复杂产品对象
    public Actor construct(ActorBuilder builder){
        Actor actor;
        builder.buildType();
        builder.buildSex();
        builder.buildFace();
        builder.buildContume();
        actor = builder.createActor();
        return actor;
    }
}

5、客户端调用方式如下

        //针对抽象构造者编程
        ActorBuilder actorBuilder;
        //通过配置文件或其他方式获取具体的建造者
        actorBuilder = new HeroBuilder();
        ActorController actorController = new ActorController();
        Actor actor;
        actor = actorController.construct(actorBuilder);
        System.out.println(actor);

6、总结

在建造者模式中,客户端只需实例化指挥者类,指挥者类针对抽象建造者编程,客户端根据需要传入
具体的建造者类型,指挥者将指导具体建造者一步一步构造一个完整的产品(逐步调用具体建造者的
buildX()方法),相同的构造过程可以创建完全不同的产品。在游戏角色实例中,如果需要更换角
色,只需要修改配置文件,更换具体角色建造者类即可;如果需要增加新角色,可以增加一个新的具
体角色建造者类作为抽象角色建造者的子类,再修改配置文件即可,原有代码无须修改,完全符合“开
闭原则”。

建造者模式的主要优点如下:
(1) 在建造者模式中,客户端不必知道产品内部组成的细节,将产品本身与产品的创建过程解耦,使
得相同的创建过程可以创建不同的产品对象。
(2) 每一个具体建造者都相对独立,而与其他的具体建造者无关,因此可以很方便地替换具体建造者
或增加新的具体建造者,用户使用不同的具体建造者即可得到不同的产品对象。由于指挥者类针对抽
象建造者编程,增加新的具体建造者无须修改原有类库的代码,系统扩展方便,符合“开闭原则”
(3) 可以更加精细地控制产品的创建过程。将复杂产品的创建步骤分解在不同的方法中,使得创建过
程更加清晰,也更方便使用程序来控制创建过程

建造者模式的主要缺点如下:
(1) 建造者模式所创建的产品一般具有较多的共同点,其组成部分相似,如果产品之间的差异性很
大,例如很多组成部分都不相同,不适合使用建造者模式,因此其使用范围受到一定的限制。
(2) 如果产品的内部变化复杂,可能会导致需要定义很多具体建造者类来实现这种变化,导致系统变
得很庞大,增加系统的理解难度和运行成本。

适用场景
在以下情况下可以考虑使用建造者模式:
(1) 需要生成的产品对象有复杂的内部结构,这些产品对象通常包含多个成员属性。
(2) 需要生成的产品对象的属性相互依赖,需要指定其生成顺序。
(3) 对象的创建过程独立于创建该对象的类。在建造者模式中通过引入了指挥者类,将创建过程封装
在指挥者类中,而不在建造者类和客户类中。
(4) 隔离复杂对象的创建和使用,并使得相同的创建过程可以创建不同的产品。

你可能感兴趣的:(架构之路,设计模式,建造者模式,java)