深入探索Java设计模式之构建器模式(五)
抽丝剥茧 细说架构那些事——【优锐课】
简单的程序不需要大量的设计过程,因为它们只关注有限的解决方案,仅使用几个类。大型程序专注于广泛的设计,该设计比好的设计范例的任何其他属性都更能利用可重用性。宏伟的想法不仅是为当前问题提供解决方案,而且是创建一种设计,为将来的变化奠定基础。复杂的程序需要数千行代码以及对象和用户之间的大量交互。这些类型的解决方案通常在使用数千台柜员机操作的空中交通管制系统和银行系统中找到。本文是在学习完优锐课JAVA架构VIP课程—【框架源码专题】中《学习源码中的优秀设计模式》后写下的学习感悟。在这里,我们探索一种称为“构建器模式”的设计模式,并使用Java代码示例对其进行实现。
总览
有效的软件设计不仅可以满足当前的要求,而且可以构成未来更改和开发的基础。说起来比在实际应用中做起来容易。但是,设计模式无疑在很大程度上减轻了代码设计的负担。模式是用于构建灵活且可维护的软件的成熟架构。它通过一套标准的规范和实践大大降低了代码的复杂性。
有许多可用的设计模式,开发人员可以根据代码流的最佳表达选择一种。不选择不符合你需求的产品几乎是不可能的。实际上,设计模式是某人已经遇到问题并设计最佳实践以获得解决方案的证明。但是,它们绝不是天意。一个更好的主意可以随时替换它们。在和平环境下的叛乱是自杀的。尽管人们可以摆脱困境并做自己的事,但在大多数情况下遵循某种设计模式是有帮助的。
构建器模式
设计模式根据其特征命名。例如,构建器模式列出了构建类结构的规范。在实例化面向对象编程中的类时特别有用。想法是将复杂对象的构造与其表示分离。它利用灵活性来设计Java之类的对象。当我们开始编码时,很容易感觉到这种设计模式的便利性。
使用构建器模式
此模式对于创建具有许多字段或属性的类的实例特别有用。显而易见的是,在这种情况下,构造函数非常麻烦。例如,在这样的类中:
public class Person {
private final long id;
private final String firstName;
private final String middleName; //optional
private final String lastName; //optional
private final Date birthDate;
private final String phone;
private final String email;
private final String street; //optional
private final String city; //optional
private final String province;
private final String zip;
// ...
要创建此类的实例,我们可以:
- 使用单个构造函数用值初始化字段
- 使用多个构造函数
- 使用无参数构造函数实例化对象后,使用setter方法
尽管这些都是语法上有效的技术,但它们在实践中非常麻烦。随着字段数量的增加,很快将变得难以管理和理解。使用单个构造函数是一个坏主意,首先是因为用庞大的参数化构造函数初始化许多字段是一个不好的设计。其次,有一些选择可以消除可选字段。使用多个构造函数不是一个好主意,因为如果将来增加字段的数量,它将很快变得难以管理。
第三种方法是根本不使用任何构造函数,而是从字段中删除final修饰符并使用setter方法进行初始化。该技术的问题在于,我们可以使用setter方法创建此类的无效对象。例如,以下内容尽管在语法上有效,但却是该类在语义上无效的实例。
Person person = new Person();
person.setCity("Mumbai");
请注意,人员对象的定义不仅是城市字段的有效初始化,而且至少是非可选字段的正确初始化。这是setter方法初始化的真正问题。
实现构建器模式
我们可以使用构建器模式来克服上面讨论的所有问题。在这里,通过这种技术,我们创建了一个称为生成器的伴随对象。此配套对象用于构造合法域对象。这不仅提高了代码的清晰度,而且使构造变得简单。
public class Person {
public static class Builder {
private long id;
private String firstName;
private String middleName; //optional
private String lastName; //optional
private Date birthDate;
private String phone;
private String email;
private String street; //optional
private String city; //optional
private String province;
private String zip;
public Builder id(final long id) {
this.id = id;
return this;
}
public Builder firstName(final String firstName) {
this.firstName = firstName;
return this;
}
public Builder middleName(final String middleName) {
this.middleName = middleName;
return this;
}
public Builder lastName(final String lastName) {
this.lastName = lastName;
return this;
}
public Builder birthDate(final Date birthDate) {
this.birthDate = birthDate;
return this;
}
public Builder phone(final String phone) {
this.phone = phone;
return this;
}
public Builder email(final String email) {
this.email = email;
return this;
}
public Builder street(final String street) {
this.street = street;
return this;
}
public Builder city(final String city) {
this.city = city;
return this;
}
public Builder province(final String province) {
this.province = province;
return this;
}
public Builder zip(final String zip) {
this.zip = zip;
return this;
}
public Person build(){
if(id <= 0 || firstName.isEmpty() ||
birthDate == null || phone.isEmpty() ||
email.isEmpty() || province.isEmpty() ||
zip.isEmpty()){
throw new IllegalStateException("Cannot create
Person object.");
}
return new Person(id,firstName,middleName,lastName,
birthDate,phone,email,street,city,province,zip);
}
}
private final long id;
private final String firstName;
private final String middleName; //optional
private final String lastName; //optional
private final Date birthDate;
private final String phone;
private final String email;
private final String street; //optional
private final String city; //optional
private final String province;
private final String zip;
private Person(final long id, final String firstName,
final String middleName, final String lastName,
final Date birthDate, final String phone,
final String email, final String street,
final String city, final String province,
final String zip) {
this.id = id;
this.firstName = firstName;
this.middleName = middleName;
this.lastName = lastName;
this.birthDate = birthDate;
this.phone = phone;
this.email = email;
this.street = street;
this.city = city;
this.province = province;
this.zip = zip;
}
}
Builder类是Person类的一部分,用于构造Person对象。对于构造函数,参数以特定方式排序。结果,它们以相同顺序传递。使用构建器模式时,顺序无关紧要,并且可以在构造过程中以任何顺序传递值。请注意,在这种情况下,构造函数被设为私有。
@Test
public void rightBuild() {
final Person.Builder builder = new Person.Builder();
final Person emp = builder
.id(101)
.firstName("Percy")
.middleName("Bysshe")
.lastName("Shelley")
.birthDate(new GregorianCalendar(1792,
Calendar.AUGUST,4).getTime())
.phone("1234567890")
.email("pbs@gmail.com")
.street("123 somewhere")
.province("someplace")
.zip("10293847").build();
}
@Test(expected = IllegalStateException.class)
public void wrongBuild() {
final Person.Builder builder = new Person.Builder();
final Person emp = builder
.middleName("Bysshe")
.lastName("Shelley")
.phone("1234567890")
.zip("10293847").build();
}
在测试方法中观察我们如何通过调用builder方法和一系列方法调用来创建对象。最后,调用build()方法以结束链并完成对象的创建。这就是我们用Java代码实现构建器模式的方式。
结论
本质是了解构建器模式背后的原理并以自己的方式实现。但是,在所有情况下,模式几乎都保持不变。如指定的那样,在必须初始化类中的大量字段的情况下,构建器模式特别有用。每个类都不适合使用此模式。可以看出,为方便起见,代码行增加了。明智地谨慎使用它。
感谢阅读!欢迎留言。想更深入探讨学习也欢迎私信我。

深入探索Java设计模式之构建器模式(五)的更多相关文章
- Java设计模式系列-装饰器模式
原创文章,转载请标注出处:<Java设计模式系列-装饰器模式> 一.概述 装饰器模式作用是针对目标方法进行增强,提供新的功能或者额外的功能. 不同于适配器模式和桥接模式,装饰器模式涉及的是 ...
- java设计模式之七装饰器模式(Decorator)
顾名思义,装饰模式就是给一个对象增加一些新的功能,而且是动态的,要求装饰对象和被装饰对象实现同一个接口,装饰对象持有被装饰对象的实例,关系图如下: Source类是被装饰类,Decorator类是一个 ...
- java设计模式之 装饰器模式
装饰器模式 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构. 这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装. 这种模式创建了一个装 ...
- Java设计模式之装饰器模式
1.装饰器模式的定义(保持接口,扩展功能) Decorate装饰器,顾名思义,就是动态的给一个对象添加一些额外的职责,就好比对房子进行装修一样. 2.装饰器模式的特征 具有一个装饰对象. 必须拥有与被 ...
- java设计模式之装饰器模式以及在java中作用
在JAVA I/O类库里有很多不同的功能组合情况,这些不同的功能组合都是使用装饰器模式实现的,下面以FilterInputStream为例介绍装饰器模式的使用 FilterInputStream和F ...
- java 设计模式 之 装饰器模式
装饰器模式的作用 在不修改原先对象核心的功能的情况下,对功能进行增强. 增强对象的功能的途径 通过类继承的方式,对父对象进行增强操作,例如造车是父类,改装跑车,跑车加大灯,改装房车,房车加私人电影院. ...
- 深入探索Java设计模式(三)之装饰器模式
装饰器模式使你可以在运行时使用类似于对象组成的技术来装饰类.这在我们希望实例化具有新职责的对象而无需对基础类进行任何代码更改的情况下尤其有用.本文是在学习完优锐课JAVA架构VIP课程—[框架源码专题 ...
- 深入探索Java设计模式(二)之策略模式
策略设计模式是Java API库中常见的模式之一.这与另一个设计模式(称为状态设计模式)非常相似.本文是在学习完优锐课JAVA架构VIP课程—[框架源码专题]中<学习源码中的优秀设计模式> ...
- 深入探索Java设计模式(四)之享元模式
享元模式适用于需要大量相同类型对象的情况.在此,设计布局可以减少创建多个对象的方式.对象在运行时会消耗资源,因此最好在内存中使用较少的对象.它减少了内存占用并利用了程序的整体性能.本文是在学习完优锐课 ...
随机推荐
- C# - VS2019 WinFrm应用程序开发报表 - ReportViewer控件初涉
前言 简单报表我们可以通过label.textBox和PrintDialog来实现,但是一般在实际生产过程中,用户的报表需求一般都是比较复杂的. 本篇主要记录对于传统中国式复杂报表的处理方法和解决思路 ...
- Nginx+SpringBoot实现负载均衡
前言 在上一篇中介绍了Nginx的安装,本篇文章主要介绍的是Nginx如何实现负载均衡. 负载均衡介绍 介绍 在介绍Nginx的负载均衡实现之前,先简单的说下负载均衡的分类,主要分为硬件负载均衡和软件 ...
- 2019-9-27:渗透测试,metasploit-framework初接触
初次利用metasploit漏洞利用框架,入侵获取win7获取权限 目标机系统:windows7,无修复补丁 目标ip地址:192.168.20.131 任务:利用ms17-010,永恒之蓝漏洞,获取 ...
- 2019-9-12:渗透测试,基础学习,Linux下用户管理笔记
linus用户管理/etc/passwd 保存用户信息/etc/shadow 保存密码信息,第二部分 !表示密码没有设置 cat /etc/passwd | grep xxx:查看特定账户信息 use ...
- Linux服务和systemctl详解
定义 A Linux service is an application (or set of applications) that runs in the background waiting to ...
- IdentityServer4 保护.net framework webapi
一.IS4服务器配置 1.新建一个Asp.net Core MVC程序,模板选择 Empty 2.Nuget添加 IdentityServer4,我这里添加的是2.5.3 3.添加Config文件, ...
- python基础-网络编程part01
软件开发架构 C/S(Client / Server) 架构 概念:是一种软件系统体系结构.Client是客户端,Server是服务端.客户端需要安装专用的客户端软件. 比如:微信.QQ.王者荣耀等应 ...
- 【JavaEE】之MyBatis输出映射
MyBatis中的输出映射有两种:resultType和resultMap. 1.resultType 使用resultType进行结果映射时,只有当查询结果中有至少一列的名称和resultType指 ...
- cbv请求分析
CBV源码分析 DRF中中所有视图都是基于CBV形式完成, 所以分析其cbv源码, 了解drf的基本请求流程就比较有必要了. urls.py """下面是一个通用的url ...
- Block循环引用问题
根控制器没办法销毁,除非程序退出 从一个控制器跳到另外一个控制器,调用该控制器的pop方法才会销毁该控制器 self是一个强指针 在block中使用self时要注意循环引用的问题 最好将当前block ...