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

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

入学报道

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

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

(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 {@Overridepublic void buildSignIn() {person.setSignIn("学生已签到");}@Overridepublic void buildProfile() {person.setProfile("学生信息已录入");}@Overridepublic void buildIdCard() {person.setIdCard("学生证已办理");}
}

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

/*** 教师入学*/
public class Teacher extends PersonBuilder {@Overridepublic void buildSignIn() {person.setSignIn("老师已签到");}@Overridepublic void buildProfile() {person.setProfile("老师个人信息已录入");}@Overridepublic void buildIdCard() {person.setIdCard("老师身份证已办理");}
}

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

/*** 职工入学*/
public class Employee extends PersonBuilder {@Overridepublic void buildSignIn() {person.setSignIn("员工已签到");}@Overridepublic void buildProfile() {person.setProfile("员工个人信息已录入");}@Overridepublic 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 {@Overridepublic void buildSignIn() {person.setSignIn("老师已签到");}@Overridepublic void buildProfile() {person.setProfile("老师个人信息已录入");}@Overridepublic void buildIdCard() {person.setIdCard("老师身份证已办理");}@Overridepublic 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.mzph.cn/news/237843.shtml

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

相关文章

Spring 5.x较上一版本的主要特性

Spring Framework 5.0 是在 2017 年发布的一个主要版本,它带来了许多改进和新特性,相比于 Spring Framework 4.x,主要的升级包括: 基于 Java 8 的基线: Spring 5 需要 Java 8 或更高版本,这使得框架得以利用…

LLaMA-Factory如何对Tokenization步骤提速

问题 数据量稍微大一些,在运行这个步骤“Running tokenizer on dataset”就要等半小时以上,然后才知道后续是否会报错。Tokenization步骤看上去并没有使用到GPU,只是在CPU上运行的。 是否有什么方法对这个步骤进行加速呢,比如多C…

c/c++实现隐藏密码

1. 我们在平常输入密码是,不能直接显示密码,应该显示*或者其它字符。 void inputPwd(char *pwd,int length) {char ch; // 用来存储getch()都进来的字符int i 0;while (1){ch getch(); /*这个函数可以实现输入不回显(输入不在终端显示)*/if (ch \r) /*密码输入结束输入回车…

Lua脚本在Redis中的高效应用

大家好,我是升仔 引言 Redis作为一个多功能的键值数据库,其性能非常出色,特别是在处理高速缓存和消息队列方面。而Lua脚本的引入,则进一步增强了Redis的能力。 1、Lua脚本与Redis的结合 Redis选择Lua作为脚本语言,主…

12.21

一、注意事项 1.CtrlShiftT用于从jar中查找类,这个eclipse键盘快捷键可以帮助快速找到类 2.更新upm和rest遇到重复解决方法 把upm文件里面多出来的三行代码删掉,右击upm文件,点击小组,点击标记为已解决,点击OK&#x…

ElasticSearch DSL Bool查询

Bool 查询的三个主要成分:must、should 和 must_not。 must: 这个条件是必须满足的。比如,你想找一本关于 Python 编程的书,那么你会在 must 里写上关键词 “Python”。 should: 这相当于你的偏好条件,…

OpenVAS 数据库管理

数据库概述为了更好地理解OpenVAS数据库管理,我们首先需要了解数据库的概念。数据库是一个组织和存储数据的软件系统,它允许用户在其中存储、访问和更新数据。在计算机系统中,数据库通常是用来存储大量数据的一个集合,这些数据可以…

Web前端-JavaScript(对象)

文章目录 1.对象1.1 概念1.2 创建对象三种方式**对象字面量创建对象**:new Object创建对象构造函数创建对象 1.3 遍历对象 2.作用域1.1 概述1.2 全局作用域1.3 局部作用域1.4 JS没有块级作用域1.5 变量的作用域1.6 作用域链1.7 预解析 1.对象 1.1 概念 什么是对象 …

Solon 开源框架,单月下载突破 250 万!!!

Solon 是什么开源项目? 一个,Java 生态型应用开发框架。它从零开始构建,有自己的标准规范与开放生态(历时六年,已有全球第二级别的生态规模)。与其他框架相比,它解决了两个重要的痛点&#xff…

jetbrains idea 报错 java.lang.ClassNotFoundException 之后自动搜索包导入包

-- 搜索类所在的包 导入包 搜索包 mac环境 pom中右键或者 cmdn

shell 的错误处理和调试方法

简介 在我们写代码过程中,一般有两个阶段:调试阶段和试运行阶段。在调试阶段我们希望尽可能的输出日志,方便在出错的时候快速定位问题。在试运行阶段希望将日志标准化,且有些错误的日志是在预期内不想展示的时候如何处理&#xff…

1. 线程概述、线程和进程、 并发和并行、多线程的优势 、程序运行原理 、主线程、 线程的 6 种状态

文章目录 1. 线程概述1.1 线程和进程1.2 并发和并行1.3 多线程的优势1.4 程序运行原理1.5 主线程 1.6 线程的 6 种状态 1. 线程概述 1.1 线程和进程 ​ 进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位…

高校/企业如何去做数据挖掘呢?

随着近年来人工智能及大数据、云计算进入爆发时期,依托三者进行的数据分析、数据挖掘服务已逐渐成为各行业进行产业升级的载体,缓慢渗透进我们的工作和生活,成为新时代升级版的智能“大案牍术”。 那么对于多数企业来说,如何做数据…

将遗留系统分解为微服务:第 2 部分

在当今不断发展的技术环境中,从整体架构向微服务的转变对于许多企业来说都是一项战略举措。这在报销计算系统领域尤其重要。正如我在上一篇文章第 1 部分应用 Strangler 模式将遗留系统分解为微服务-CSDN博客中提到的,让我们探讨如何有效管理这种转变。 …

Kylin的工作原理及使用分享:构建大数据分析之塔

学习目标: 了解Kylin的工作原理和基本概念理解Kylin在大数据分析中的作用和价值学会使用Kylin进行数据建模、数据预处理和查询 学习内容: 什么是Kylin? Kylin是一个开源的分布式分析引擎,专注于大数据的实时多维分析。它能够通过…

Appium Server 启动失败常见原因及解决办法

Error: listen EADDRINUSE: address already in use 0.0.0.0:4723 如下图: 错误原因:Appium 默认的4723端口被占用 解决办法: 出现该提示,有可能是 Appium Server 已启动,关闭已经启动的 Appium Server 即可。472…

Python---案例-多任务版TCP服务端程序开发

1. 需求 目前我们开发的TCP服务端程序只能服务于一个客户端,如何开发一个多任务版的TCP服务端程序能够服务于多个客户端呢? 完成多任务,可以使用线程,比进程更加节省内存资源。 2. 具体实现步骤 编写一个TCP服务端程序,循环等…

Alien Skin Exposure 7汉化破解版下载 V 7.1.0.214 中文注册版

软件介绍 Alien Skin Exposure 7是一款超好用的PS胶片效果调色滤镜,它为数码照片提供胶片的曝光,还包括模仿胶片的颗粒感,并且可以控制胶片颗粒的分布,能够帮助用户对图片进行更好的处理! 软件特色 1、支持RAW格式&a…

node-red:使用node-red-contrib-amqp节点,实现与RabbitMQ服务器(AMQP)的消息传递

node-red-contrib-amqp节点使用 一、简介1.1 什么是AMQP协议?1.2 什么是RabbitMQ? -> 开源的AMQP协议实现1.3 RabbitMQ的WEB管理界面介绍1.3 如何实现RabbitMQ的数据采集? -> node-red 二、node-red-contrib-amqp节点安装与使用教程2.1 节点安装2.2 节点使用2.2.1 amq…

Ultra Mobile PayGO购买充值激活

一、前言 Ultra Mobile PayGO免费无限拨打 80 多个国际目的地,还可以向 190 多个国际目的地发送短信。在现在ai智能时代,我自己也需要一张这样的卡,今天用fomepay的虚拟卡激活了这张电话卡,根据需要按套餐购买。 二、点击申请fom…