首页 > 编程语言 >设计模式-建造者模式在Java中使用示例

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

时间:2023-07-13 18:14:25浏览次数:51  
标签:Java 角色 示例 创建 建造 actor 模式 设计模式 public

场景

建造者模式

复杂对象的组装与创建

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

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

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

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

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

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

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

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

建造者模式举例

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

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

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

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

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

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

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

建造者模式结构图与角色

 

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

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

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

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

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

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

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

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

https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/127539695

注:

博客:
https://blog.csdn.net/badao_liumang_qizhi

实现

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

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,角色,示例,创建,建造,actor,模式,设计模式,public
From: https://www.cnblogs.com/badaoliumangqizhi/p/17551726.html

相关文章

  • spring bean 的属性为 java.util.Properties 时如何初始化该属性
       publicclassFooBean{privatejava.util.Propertiesattr;publicjava.util.PropertiesgetAttr(){returnattr;}publicvoidsetAttr(java.util.Propertiesattr){this.attr=attr;}} <beanid=......
  • Java如何将数组转换为集合?
    在Java中,可以使用`Arrays`类的`asList()`方法将数组转换为集合。该方法接受一个数组作为参数,并返回一个包含数组元素的固定大小的列表。以下是将数组转换为集合的示例:String[]array={"item1","item2","item3"};List<String>list=Arrays.asList(array);在上述示例中,......
  • JavaScript 中获取数组最后一个元素3种方法及性能
    当需要从JavaScript中的数组中获取最后一个元素时,有多种选择,本文将提供3种可用方法。1.数组length属性length属性返回数组中元素的数量。从数组的长度中减去1得到数组最后一个元素的索引,使用它可以访问最后一个元素。从长度中减去1的原因是,在JavaScript中,数组索引......
  • java 加载bean
    @Service@AutowiredprivateActionLogAspectactionLogAspect;@RestController@RequiredArgsConstructorprivatefinalImComplaintServiceimComplaintService;@Slf4j@RequiredArgsConstructor@ComponentfinalActionLogAspectactionLogAspect;......
  • 发送请求忘记指定协议方式,日志com.jcraft.jsch.JSchException: java.net.ConnectExcep
      2023-07-1319:06:51.487-ERROR17629---[http-nio-192.168.2.206-36093-exec-8]c.t.b.p.b.c.common.util.sftp.SftpPool:com.jcraft.jsch.JSchException:java.net.ConnectException:拒绝连接(Connectionrefused)_atcom.jcraft.jsch.Util.createSocket(......
  • Java反序列化:URLDNS的反序列化调试分析
    URLDNS链子是Java反序列化分析的第0课,网上也有很多优质的分析文章。笔者作为Java安全初学者,也从0到1调试了一遍,现在给出调试笔记。一.Java反序列化前置知识Java原生链序列化:利用Java.io.ObjectInputStream对象输出流的writerObject方法实现Serializable接口,将对象转化成字节......
  • Java空指针异常优雅处理的方式
    1原因如下:由于Java开发过程中一不注意就会造成空指针异常,但是如果要避免这些空指针异常我们就可能需要写如下啰嗦有无聊的语句:if(test!=null&&test.size()>0){..............}为了避免写这些无聊的语句和避免NPE错误,我们可以用如下用法进行替代。......
  • java项目配置druid监控页面
    druid监控页面如图: 满足条件:1.项目引入了druid相关的jar包 2.项目加入druid相关的配置#####druid监控#####WebStatFilter配置spring.datasource.druid.web-stat-filter.enabled=truespring.datasource.druid.web-stat-filter.url-pattern=/*spring.datasource.......
  • FIX tutorial in Java with QuickFIX/j simple example
    http://www.tuicool.com/articles/v2me6r 时间 2014-07-3112:22:00ArulkumaranKumaraswamipillaiblog主题Log4J Q.WhatisFIXProtocol? A.FIXstandsforFinancialInformationeXchange,whichisanopenprotocolintendedtostre......
  • 解决查看java占用的端口的具体操作步骤
    查看Java占用的端口在开发和运维过程中,我们经常需要查看Java应用程序所占用的端口。这对于排查问题、调试和监控都非常重要。本文将介绍几种方法来查看Java占用的端口,并提供相应的代码示例。方法一:使用jps命令jps命令是Java开发工具包(JDK)自带的一个命令行工具,用于查看Java进程的......