【设计模式-2.5】创建型——建造者模式

news2024/9/22 7:25:13

说明:本文介绍设计模式中,创建型设计模式中的最后一个,建造者模式;

入学报道

创建型模式,关注于对象的创建,建造者模式也不例外。假设现在有一个场景,高校开学,学生、教师、职工都要办理相关的报道手续,如签到、个人信息录入、分配身份证明(学生证、教师证、职工证)等等;

首先,创建一个抽象类,如下:

(Person,人员类,有签到、个人信息、身份证明属性)

/**
 * 人员
 */
public class Person {

    /**
     * 签到
     */
    private String signIn;

    /**
     * 个人信息
     */
    private String profile;

    /**
     * 身份证明
     */
    private String idCard;

    public String getSignIn() {
        return signIn;
    }

    public void setSignIn(String signIn) {
        this.signIn = signIn;
    }

    public String getProfile() {
        return profile;
    }

    public void setProfile(String profile) {
        this.profile = profile;
    }

    public String getIdCard() {
        return idCard;
    }

    public void setIdCard(String idCard) {
        this.idCard = idCard;
    }
}

在创建具体对象之前,先创建一个抽象的建造者类,用于统一方法,定义人员对象;

(PersonBuilder,人员建造者)

/**
 * 抽象建造者
 */
public abstract class PersonBuilder {

    Person person = new Person();

    /**
     * 签到行为
     */
    public abstract void buildSignIn();

    /**
     * 录入个人信息
     */
    public abstract void buildProfile();

    /**
     * 办理身份证明
     */
    public abstract void buildIdCard();

    /**
     * 建造完成
     * @return
     */
    public Person build() {
        return person;
    }
}

(Student,学生类,继承人员建造者,重写学生入学相关方法)

/**
 * 学生入学
 */
public class Student extends PersonBuilder {
    @Override
    public void buildSignIn() {
        person.setSignIn("学生已签到");
    }

    @Override
    public void buildProfile() {
        person.setProfile("学生信息已录入");
    }

    @Override
    public void buildIdCard() {
        person.setIdCard("学生证已办理");
    }
}

(Teacher,教师类,继承人员建造者,重写教师入学相关方法)

/**
 * 教师入学
 */
public class Teacher extends PersonBuilder {
    @Override
    public void buildSignIn() {
        person.setSignIn("老师已签到");
    }

    @Override
    public void buildProfile() {
        person.setProfile("老师个人信息已录入");
    }

    @Override
    public void buildIdCard() {
        person.setIdCard("老师身份证已办理");
    }
}

(Employee,职工类,继承人员建造者,重写职工入学相关方法)

/**
 * 职工入学
 */
public class Employee extends PersonBuilder {
    @Override
    public void buildSignIn() {
        person.setSignIn("员工已签到");
    }

    @Override
    public void buildProfile() {
        person.setProfile("员工个人信息已录入");
    }

    @Override
    public void buildIdCard() {
        person.setIdCard("员工身份证已办理");
    }
}

再创建一个建造者控制类,协调入学后的具体事宜,如先签到、后录入个人信息,最后才发身份证明,返回建造完成的人员对象;

(PersonController,人员入学控制器)

/**
 * 人员入学控制器
 */
public class PersonController {

    /**
        * 人员入学
        * @return
        */
        public Person construct(PersonBuilder personBuilder) {
            personBuilder.buildSignIn();
            personBuilder.buildProfile();
            personBuilder.buildIdCard();
            return personBuilder.build();
        }
}

(Client,客户端,演示人员入学过程)

/**
 * 客户端
 */
public class Client {
    public static void main(String[] args) {
        // 一个学生入学
        Person student = new PersonController().construct(new Student());
        System.out.println(student.getSignIn());
        System.out.println(student.getProfile());
        System.out.println(student.getIdCard());

        System.out.println("=====================================");

        // 一个老师入学
        Person teacher = new PersonController().construct(new Teacher());
        System.out.println(teacher.getSignIn());
        System.out.println(teacher.getProfile());
        System.out.println(teacher.getIdCard());
    }
}

(执行结果,可见对象已创建完成)

在这里插入图片描述

改进与优化

在《设计模式的艺术》(第一版,刘伟著)中,作者关于PersonController(人员控制器)类的作用,有两点改进与优化的地方,如下:

改进:可省略PersonController

可在抽象建造者类PersonBuilder(人员建造者)中定义一个静态的Person变量,这样就不需要额外设立一个PersonController类了,如下:

(PersonBuilder,抽象人员建造者,既统一了方法,也完成了建造的流程)

/**
 * 抽象建造者
 */
public abstract class PersonBuilder {

    /**
     * 定义一个抽象的Person
     */
    protected static Person person = new Person();

    /**
     * 签到行为
     */
    public abstract void buildSignIn();

    /**
     * 录入个人信息
     */
    public abstract void buildProfile();

    /**
     * 办理身份证明
     */
    public abstract void buildIdCard();

    /**
     * 建造Person
     * @return
     */
    public static Person build(PersonBuilder personBuilder) {
        personBuilder.buildSignIn();
        personBuilder.buildProfile();
        personBuilder.buildIdCard();
        return person;
    }
}

(Client,客户端,使用人员建造者的build()方法建造对象)

/**
 * 客户端
 */
public class Client {
    public static void main(String[] args) {
        // 一个学生入学
        Person student = PersonBuilder.build(new Student());
        System.out.println(student.getSignIn());
        System.out.println(student.getProfile());
        System.out.println(student.getIdCard());

        System.out.println("=====================================");

        // 一个老师入学
        Person teacher = PersonBuilder.build(new Teacher());
        System.out.println(teacher.getSignIn());
        System.out.println(teacher.getProfile());
        System.out.println(teacher.getIdCard());
    }
}

(执行效果相同)

在这里插入图片描述

优化:细化建造过程

可以定义一个“钩子”方法,“钩子”方法一般是“isXXX”命名的,返回值为boolean类型。利用“钩子”方法,规定某些人员可以跳过或者必须执行某方法,来细化对象建造的流程。如规定教师人员的建造,因为教师流动不大,可以跳过录入信息流程。

就可以在PersonBuilder类中定义一个“钩子”方法,默认返回true,即默认所有人员都需要录入个人信息。如下:

/**
 * 抽象建造者
 */
public abstract class PersonBuilder {

    /**
     * 定义一个抽象的Person
     */
    protected static Person person = new Person();

    /**
     * 签到行为
     */
    public abstract void buildSignIn();

    /**
     * 录入个人信息
     */
    public abstract void buildProfile();

    /**
     * 办理身份证明
     */
    public abstract void buildIdCard();

    /**
     * 钩子方法:表示默认所有人都需要经过buildProfile()方法,具体由子类实现
     */
    public boolean isBuildProfile() {
        return true;
    }

    /**
     * 建造Person
     * @return
     */
    public static Person build(PersonBuilder personBuilder) {
        personBuilder.buildSignIn();
        // 根据钩子方法判断是否需要buildProfile()
        if (personBuilder.isBuildProfile()) {
            personBuilder.buildProfile();
        }
        personBuilder.buildIdCard();
        return person;
    }
}

教师类中,可以重写这个“钩子”方法,表示不需要执行录入个人信息这个流程了。

/**
 * 教师入学
 */
public class Teacher extends PersonBuilder {
    @Override
    public void buildSignIn() {
        person.setSignIn("老师已签到");
    }

    @Override
    public void buildProfile() {
        person.setProfile("老师个人信息已录入");
    }

    @Override
    public void buildIdCard() {
        person.setIdCard("老师身份证已办理");
    }

    @Override
    public boolean isBuildProfile() {
        return false;
    }
}

客户端代码不变,执行

/**
 * 客户端
 */
public class Client {
    public static void main(String[] args) {
        // 一个学生入学
        Person student = PersonBuilder.build(new Student());
        System.out.println(student.getSignIn());
        System.out.println(student.getProfile());
        System.out.println(student.getIdCard());

        System.out.println("=====================================");

        // 一个老师入学
        Person teacher = PersonBuilder.build(new Teacher());
        System.out.println(teacher.getSignIn());
        System.out.println(teacher.getProfile());
        System.out.println(teacher.getIdCard());
    }
}

执行结果可以看到教师确实是没有执行录入个人信息的方法,但是因为Person是static修饰的属性,打印的是上面学生的值。

在这里插入图片描述

那么,如果避免这个问题值得思考,或者就不省略PersonController类。

小结

建造者模式,通过定义一个抽象建造者类,封装了对象创建的细节,另外通过“钩子”方法,可细化对象创建过程,降低了系统复杂度,维护了系统的灵活性和扩展性。

总结

本文参考《设计模式的艺术》、《秒懂设计模式》两书

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【新版HI3559AV100开发注意事项(二)】

#新版HI3559AV100开发注意事项(二) 十一、请问海思HI3559AV100 SPC030资料里面的HI3559ADMEB_VER_C_PCB.pcb是用什么软件打开啊? 答:PADS VX 2.2 Altium designer 十二、hi3559级联问题请教 在SDK的文档中只看到了两块Hi3559板…

ARM GIC(一) cortex-A 处理器中断简介

对于ARM的处理器,中断给处理器提供了触觉,使处理器能够感知到外界的变化,从而实时的处理。本系列博文,是以ARM cortex-A系列处理器,来介绍ARM的soc中,中断的处理。 ARM cortex-A系列处理器,提供了4个管脚给soc,实现外界中断的传递。分别是: nIRQ: 物理普通中断 nF…

利用Spark构建房价分析与推荐系统:基于58同城数据的大数据实践

利用Spark构建房价分析与推荐系统:基于58同城数据的大数据实践 基于Spark的房价数据分析预测推荐系统引言技术栈功能概述项目实现1. 数据爬取与处理2. 大数据分析与可视化3. 房价预测模型4. 协同过滤推荐系统5. Web应用开发6. 数据管理与用户管理 总结与展望 基于Sp…

优维科技荣获第二届中国赛宝信息技术应用创新优秀解决方案三等奖

近日,“第二届中国赛宝信息技术应用创新优秀解决方案”评选活动圆满结束。优维科技所提交的《Hyperlnsight超融合持续观测解决方案》、《EasyOps一体化运维平台》从全国近300份申报方案中脱颖而出,荣获2023中国赛宝信息技术应用创新优秀解决方案奖。 本…

Python - 深夜数据结构与算法之 Tree

目录 一.引言 二.树与二叉树简介 1.Tree 树 2.Binary Tree 二叉树 3.Binary Search Tree 二叉搜索树 三.经典算法实战 1.In-Order-Traversal [94] 2.Pre-Order-Traversal [144] 3.Fib [509] 4.N-Tree-Pre-Order-Traversal [589] 5.N-Tree-Post-Order-Traversal [590…

改变传媒格局的新趋势

在如今信息高速发展的时代,人们早已进入了一个以手机为中心的智能化时代。随着科技的迅猛发展,手机无人直播成为了一种新兴的传媒形态,正逐渐改变着传媒格局。本文将从手机无人直播的定义、发展背景和影响等方面进行探讨。 首先,…

浏览器缓存机制(详)

目录 1,缓存的分类1.1,按缓存位置1,Service Worker2,Memory Cache3,Disk Cache4,Push Cache 1.2,按缓存类型强缓存ExpiresCache-control 协商缓存Last-Modified & If-Modified-SinceEtag &a…

【优化】XXLJOB修改为使用虚拟线程

【优化】XXLJOB修改为使用虚拟线程 新建这几个目录 类&#xff0c; 去找项目对应的xxljob的源码 主要是将 new Thread 改为 虚拟线程 Thread.ofVirtual().name("VT").unstarted 以下代码是 xxljob 2.3.0版本 举一反三 去修改对应版本的代码 <!-- 定…

UG螺旋线命令的使用

螺旋线按照螺距类型可以分为两种类型&#xff1a; 1、等螺距螺旋线 2、变螺距螺旋线 等螺距螺旋线 变螺距螺旋线 沿矢量螺旋线 沿矢量螺旋线-线性大小和螺距 沿矢量螺旋线-沿脊线的线性 沿矢量螺旋线-沿脊线的线性 当我们想模拟弹簧被拉伸或压缩状态时&#xff0c;可以使用…

Python-基于fastapi实现SSE流式返回(类似GPT)

最近在做大模型对话相关功能&#xff0c;需要将对话内容流式返回给前端页面&#xff08;类似GPT的效果&#xff09;。下面直接说下如何实现&#xff1a; 1.首先导入fastapi和sse流式返回所需要的包 from fastapi import APIRouter, Response, status from sse_starlette.sse …

智能化运输与航空航天:发展历程、问题与未来趋势

导言 智能化运输与航空航天是当前科技领域的研究热点之一&#xff0c;本文将深入研究这一领域的发展历程、遇到的问题、解决过程&#xff0c;以及未来的可用范围。同时&#xff0c;我们将探讨各国在这一领域的应用情况和未来的研究趋势&#xff0c;分析在哪些方面能够取胜&…

Java操作Word修订功能:启用、接受、拒绝、获取修订

Word的修订功能是一种在文档中进行编辑和审阅的功能。它允许多个用户对同一文档进行修改并跟踪这些修改&#xff0c;以便进行审查和接受或拒绝修改。修订功能通常用于团队合作、专业编辑和文件审查等场景。 本文将从以下几个方面介绍如何使用免费工具Free Spire.Doc for Java在…

数据挖掘体系介绍

数据挖掘是什么&#xff1f; 简而言之&#xff0c;对数据进行挖掘&#xff0c;从中提取出有效的信息。一般我们会把这种信息通过概念、规则、规律、模式等有组织的方式展示出来&#xff0c;形成所谓的知识。特别是在这个大数据时代&#xff0c;当数据多到一定程度&#xff0c;…

shell 数组的详细用法

简介 数组是一种数据结构&#xff0c;用于存储和处理一组相关的数据元素。数组可以包含多个值&#xff0c;每个值都有一个索引&#xff0c;用于标识和访问它们。 目录 1. 数组的基本用法 1.1. 定义数组的方式 1.1.1. 直接赋值 1.1.2. declare声明数组 1.1.3. 索引赋值 1.…

山景DU561—32位高性能音频处理器(DSP)芯片

音频处理可以更好地捕捉和处理声音和音乐&#xff1b;而DSP音频处理芯片是一种利用数字信号处理技术进行音频处理的专用芯片&#xff1b;可用于多种应用&#xff0c;从音乐拾音到复杂的音频信号处理&#xff0c;和声音增强。 由工采网代理的山景DU561是一款集成多种音效算法高…

YOLOv5改进 | 卷积篇 | 通过RFAConv重塑空间注意力(深度学习的前沿突破)

一、本文介绍 本文给大家带来的改进机制是RFAConv&#xff0c;全称为Receptive-Field Attention Convolution&#xff0c;是一种全新的空间注意力机制。与传统的空间注意力方法相比&#xff0c;RFAConv能够更有效地处理图像中的细节和复杂模式(适用于所有的检测对象都有一定的…

CentOS安装Python解释,CentOS设置python虚拟环境,linux设置python虚拟环境

一、安装python解释器 1、创建解释器安装的目录&#xff1a;/usr/local/python39 cd /usr/local mkdir python39 2、下载依赖 yum -y install zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel tk-devel gcc make libffi-devel xz-devel …

MyBatis——MyBatis的ORM映射和MyBatis的配置文件升级

1.MyBatis的ORM映射 拷贝之前的工程&#xff1a; 1.1.什么是ORM映射 MyBatis只能自动维护库表”列名“与”属性名“相同时的对应关系&#xff0c;二者不同时无法自动ORM&#xff0c;如下&#xff1a; 1.2.列的别名 在SQL中使用 as 为查询字段添加列别名&#xff0c;以匹配…

Gin之GORM事务(转账操作)

禁用默认事务的操作 为了确保数据一致性,GORM 会在事务里执行写入操作(创建、更新、删除)。如果没有这方面的要求,您可以在初始化时禁用它,这将获得大约 30%+ 性能提升。 // 全局禁用 db, err := gorm.Open(sqlite.Open("gorm.db"), &gorm.Config{SkipDef…

CCF编程能力等级认证GESP—C++6级—20230923

CCF编程能力等级认证GESP—C6级—20230923 单选题&#xff08;每题 2 分&#xff0c;共 30 分&#xff09;判断题&#xff08;每题 2 分&#xff0c;共 20 分&#xff09;编程题 (每题 25 分&#xff0c;共 50 分)小杨买饮料小杨的握手问题 答案及解析单选题判断题编程题1编程题…