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

场景

建造者模式

复杂对象的组装与创建

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

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

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

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

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

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

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

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

建造者模式举例

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

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

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

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

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

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

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

建造者模式结构图与角色

 

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

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) 隔离复杂对象的创建和使用,并使得相同的创建过程可以创建不同的产品。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/37139.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Windows git bash输入vim报错,不能使用vim-plug插件管理器

Windows系统下的git bash在安装时自带了默认的vim&#xff0c;我自己也下了个gvim&#xff0c;并且配置了.vimrc&#xff0c;其中使用了vim-plug管理nerdtree这些插件。但是在bash中vim <file>时&#xff0c;就会蹦出来几行报错&#xff1a; 处理 /c/Users/<username…

Redis报错-CROSSSLOT keys in request don‘t hash in the same slot

背景 问题涉及&#xff1a;spring security、spring session、redis 问题描述 springbootspringsecurityspringsessionantd 登录功能的时候&#xff0c;在源码中使用到了redis的rename命令&#xff08;如下图所示&#xff09; 在这里就会报错 CROSSSLOT keys in request d…

Shell通配符和正则表达式

目录 ​​​​​​​grep 通配符 正则表达式 grep grep家族有三大成员分别为&#xff1a; grep&#xff1a;支持使用基本正则表达式。 egrep&#xff1a;支持使用扩展正则表达式。 fgrep&#xff1a;不支持使用正则表达式&#xff0c;即所有的正则表达式中的元字符都将作…

网络安全(黑客技术)自学笔记

首先给大家简单介绍一下网络安全&#xff1a; 1.什么是网络安全&#xff1f; 网络安全可以基于攻击和防御视角来分类&#xff0c;我们经常听到的 “红队”、“渗透测试” 等就是研究攻击技术&#xff0c;而“蓝队”、“安全运营”、“安全运维”则研究防御技术。 无论网络、…

感受C++模版的所带来的魅力

一、泛型编程思想 首先我们来看一下下面这三个函数&#xff0c;如果学习过了 C函数重载 和 C引用 的话&#xff0c;就可以知道下面这三个函数是可以共存的&#xff0c;而且传值会很方便 void Swap(int& left, int& right) {int temp left;left right;right temp; }…

基于Java+Swing+Mysql影院购票系统

基于JavaSwingMysql影院购票系统 一、系统介绍二、功能展示1.用户登陆2.用户订票管理3.电影售票中心4.电影上映管理4.退票记录查询 三、数据库四、其他系统实现五、获取源码 一、系统介绍 该系统实现了查看管理员登陆、用户订票管理、电影上映管理、电影售票中心、退票记录查询…

vue的学习

title: VUE 一、Vue简介 1.1 简介 ::: tip Vue (读音 /vjuː/&#xff0c;类似于 view) 是一套用于构建用户界面的渐进式的js框架&#xff0c;发布于 2014 年 2 月。与其它大型框架不同的是&#xff0c;Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层&#xff0…

我对运维初学者的几点小建议

我对运维初学者的几点小建议 在此分享一下运维的职业规划和Linux学习的路线。希望给正在做运维工作或者准备入行运维这行的同学一些启发和帮助。 首先在学习Linux之前&#xff0c;我个人其实非常建议先把计算机基础知识学习好的。这些基础十分重要&#xff0c;别看都是一些理论…

使用Lambda表达式对List<Map<String,Object>>中key值相同的Map进行分组合并

现有两张表A表和B表&#xff0c;A表存放的是各省市的认证次数&#xff0c;B表存放的是各省市的申领次数&#xff0c;重点关注dq,cs这两个字段&#xff0c;其他的字段可忽略 A表&#xff08;省市认证次数表&#xff09; B表&#xff08;省市申领次数表&#xff09; 项目中有以下…

qt完整教程

各个组件的意思(功能介绍) Python Qt GUI设计:UI界面可视化组件、属性概述(基础篇—3)-腾讯云开发者社区-腾讯云 qt 如何设计好布局和漂亮的界面。_qt界面_花狗Fdog的博客-CSDN博客 样式表(美化关键)/*灰色*/ Q/*灰色*/ QWidget {background-color: rgb(255, 182, …

MySQL-概述-数据模型SQL简介

数据库&#xff1a;DataBase&#xff08;DB&#xff09;&#xff0c;是存储和管理数据的仓库数据库管理系统&#xff1a;DataBase Management System&#xff08;DBMS&#xff09;&#xff0c;操作和管理数据库的大型软件。SQL&#xff1a;Structured Query Language&#xff0…

汇报方案设计方案规划方案资源下载

标题汇报方案设计方案规划方案资源下载https://wheart.cn/so/home?mdw&tag%E5%AE%89%E5%85%A8文章标签事业单位人事人才信息综合管理系统建设设计报价方案人事系统,人事人才,事业单位,工资系统,职称系统xx纪检委智慧监督平台建设方案汇报.docx建设方案,规划设计,汇报方案营…

【C++】priority_queue使用与模拟实现

认识priority_queue 1、priority_queue(优先级队列)是一种容器适配器&#xff0c;底层是一个完全二叉树的大堆&#xff08;堆总是一颗完全二叉树&#xff0c;根结点最大的堆叫做大堆&#xff1b;根结点最小的堆叫做小堆&#xff09;&#xff0c;头文件在queue中&#xff0c;根…

入侵排查与响应-window和linux版

目录 &#xff08;一&#xff09;关于这方面的一些简单了解 1、我们的电脑为什么会被黑客入侵 2、黑客攻击的方式 &#xff08;二&#xff09;window入侵排查 1、查看异常特征 2、系统账户安全 3、检测异常端口、进程 4、查看启动项、计划任务、服务 5、检查系统相关信…

Spring Cloud微服务治理框架深度解析

在学习一个技术之前&#xff0c;首先我们要了解它是做什么的&#xff0c;我们为什么要用它。不然看再多资料都理解不了&#xff0c;因此我们先来讲解下Spring Cloud Spring Cloud是一套微服务治理框架&#xff0c;几乎考虑到了微服务治理的方方面面。那么接下来具体说下 Spring…

Linux 的常用命令

文章目录 lsllcdpwd编辑简单文件touchcatecho 编辑复杂文件vim mkdirrmcpmvgerppsnetstat总结 ls 查看当前目录或指定目录下的所有文件 ls 什么都不加表示查看当前目录中的内容 ls目录名&#xff0c;就是插卡指定目录下的所有文件。/代表根目录。 注&#xff1a;蓝色的表示目…

【Leetcode】42.接雨水(困难)

一、题目 1、题目描述 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。 示例1: 输入:height = [0,1,0,2,1,0,1,3,2,1,2,1] 输出:6 解释:上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6…

OpenCV实现一张图片的特定区域上添加另一张图片

#include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> using namespace cv;int main( ){Mat image= imread

java并发编程 10:AQS

目录 什么是AQS原理 什么是AQS juc包的结构如下图&#xff1a; AQS就是AbstractQueuedSynchronizer&#xff0c;是个抽象类&#xff0c;实现了自己的一些方法。它是阻塞式锁和相关的同步器工具的框架。很多并发类都是基于它实现的&#xff0c;如&#xff1a;ReentrantLock、Co…

Edge浏览器无法展示Stable Diffusion Control Net插件

Edge浏览器无法展示Stable Diffusion Control Net插件 最近在学习Stable Diffusion&#xff0c;需要使用到Control Net插件&#xff0c;结果通过各种方式安装成功插件后&#xff0c;浏览器页面没有展示ControlNet相关页面&#xff0c;最终换到Chorme浏览器后正常&#xff0c;猜…