深入探索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设计模式(四)之享元模式
享元模式适用于需要大量相同类型对象的情况.在此,设计布局可以减少创建多个对象的方式.对象在运行时会消耗资源,因此最好在内存中使用较少的对象.它减少了内存占用并利用了程序的整体性能.本文是在学习完优锐课 ...
随机推荐
- Java开发中常用jar包整理及使用
本文整理了我自己在Java开发中常用的jar包以及常用的API记录. <!-- https://mvnrepository.com/artifact/org.apache.commons/com ...
- 50.Qt-QJsonDocument读写json
QJsonDocument: 提供一种读取和写入JSON文档的方法,可以通过它的的成员函数array()或object()检索文档中包含的数组或对象,然后读取JSON数据,或者修改数据. QJsonO ...
- Zxing QRCode
1.拉伸 2.只能扫描一次 3.空指针异常
- pwnable.kr第二天
3.bof 这题就是简单的数组越界覆盖,直接用gdb 调试出偏移就ok from pwn import * context.log_level='debug' payload='A'*52+p32(0 ...
- Spring框架AOP学习总结(下)
目录 1. AOP 的概述 2. Spring 基于AspectJ 进行 AOP 的开发入门(XML 的方式): 3.Spring 基于AspectJ 进行 AOP 的开发入门(注解的方式): 4.S ...
- C#变量---xdd
cshape(c#)学习笔记 1. string str1=Console.ReadLine();//键盘输入的默认为字符串 2. Console.WriteLine('你的成绩是'+a+'分'); ...
- Netty Pipeline与ChannelHandler那些事
Pipeline和ChannelHandler是Netty处理流程的重要组成部分,ChannelHandler对应一个个业务处理器,Pipeline则是负责将各个ChannelHandler串起来的& ...
- NTP服务搭建详解一条龙
说在前面:ntp和ntpdate区别 ①两个服务都是centos自带的(centos7中不自带ntp).ntp的安装包名是ntp,ntpdate的安装包是ntpdate.他们并非由一个安装包提供. ② ...
- js中this的使用及代表意义
我们在js中经常看到this这个关键字,那么他是什么呢?它可以是全局对象.当前对象,也可以是任意对象,函数的调用方式决定了 this 的值. 1. 方法中的this. 在对象方法中, this 指向调 ...
- map.entrySet().iterator()
1.首先创建一个HashMap, Map map= new HashMap(); 2.Iterator iter= map.entrySet().iterator(); 首先是map.entrySet ...