抽丝剥茧 细说架构那些事——【优锐课】

简单的程序不需要大量的设计过程,因为它们只关注有限的解决方案,仅使用几个类。大型程序专注于广泛的设计,该设计比好的设计范例的任何其他属性都更能利用可重用性。宏伟的想法不仅是为当前问题提供解决方案,而且是创建一种设计,为将来的变化奠定基础。复杂的程序需要数千行代码以及对象和用户之间的大量交互。这些类型的解决方案通常在使用数千台柜员机操作的空中交通管制系统和银行系统中找到。本文是在学习完优锐课JAVA架构VIP课程—【框架源码专题】中《学习源码中的优秀设计模式》后写下的学习感悟。在这里,我们探索一种称为“构建器模式”的设计模式,并使用Java代码示例对其进行实现。

深入探索Java设计模式(一)之单例模式

深入探索Java设计模式(二)之策略模式

深入探索Java设计模式(三)之装饰器模式

深入探索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设计模式之构建器模式(五)的更多相关文章

  1. Java设计模式系列-装饰器模式

    原创文章,转载请标注出处:<Java设计模式系列-装饰器模式> 一.概述 装饰器模式作用是针对目标方法进行增强,提供新的功能或者额外的功能. 不同于适配器模式和桥接模式,装饰器模式涉及的是 ...

  2. java设计模式之七装饰器模式(Decorator)

    顾名思义,装饰模式就是给一个对象增加一些新的功能,而且是动态的,要求装饰对象和被装饰对象实现同一个接口,装饰对象持有被装饰对象的实例,关系图如下: Source类是被装饰类,Decorator类是一个 ...

  3. java设计模式之 装饰器模式

    装饰器模式 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构. 这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装. 这种模式创建了一个装 ...

  4. Java设计模式之装饰器模式

    1.装饰器模式的定义(保持接口,扩展功能) Decorate装饰器,顾名思义,就是动态的给一个对象添加一些额外的职责,就好比对房子进行装修一样. 2.装饰器模式的特征 具有一个装饰对象. 必须拥有与被 ...

  5. java设计模式之装饰器模式以及在java中作用

    在JAVA I/O类库里有很多不同的功能组合情况,这些不同的功能组合都是使用装饰器模式实现的,下面以FilterInputStream为例介绍装饰器模式的使用  FilterInputStream和F ...

  6. java 设计模式 之 装饰器模式

    装饰器模式的作用 在不修改原先对象核心的功能的情况下,对功能进行增强. 增强对象的功能的途径 通过类继承的方式,对父对象进行增强操作,例如造车是父类,改装跑车,跑车加大灯,改装房车,房车加私人电影院. ...

  7. 深入探索Java设计模式(三)之装饰器模式

    装饰器模式使你可以在运行时使用类似于对象组成的技术来装饰类.这在我们希望实例化具有新职责的对象而无需对基础类进行任何代码更改的情况下尤其有用.本文是在学习完优锐课JAVA架构VIP课程—[框架源码专题 ...

  8. 深入探索Java设计模式(二)之策略模式

    策略设计模式是Java API库中常见的模式之一.这与另一个设计模式(称为状态设计模式)非常相似.本文是在学习完优锐课JAVA架构VIP课程—[框架源码专题]中<学习源码中的优秀设计模式> ...

  9. 深入探索Java设计模式(四)之享元模式

    享元模式适用于需要大量相同类型对象的情况.在此,设计布局可以减少创建多个对象的方式.对象在运行时会消耗资源,因此最好在内存中使用较少的对象.它减少了内存占用并利用了程序的整体性能.本文是在学习完优锐课 ...

随机推荐

  1. 理解Redis的反应堆模式

    1. Redis的网络模型 Redis基于Reactor模式(反应堆模式)开发了自己的网络模型,形成了一个完备的基于IO复用的事件驱动服务器,但是不由得浮现几个问题: 为什么要使用Reactor模式呢 ...

  2. Docker-Compose基础与实战,看这一篇就够了

    what & why Compose 项目是 Docker 官方的开源项目,负责实现对 Docker 容器集群的快速编排.使用前面介绍的Dockerfile我们很容易定义一个单独的应用容器.然 ...

  3. linux网络配置(iproute2)

    iproute2家族 ip命令:show  / manipulate routing,devices,policy routing and tunnels(显示/操纵路由.设备.策略路由和隧道) 语法 ...

  4. Java基础面试题及答案(一)

    Java 基础部分 1. JDK 和 JRE 有什么区别? JDK:Java Development Kit 的简称,java 开发工具包,提供了 java 的开发环境和运行环境. JRE:Java ...

  5. js模块导入/导出大全

    说明 module.exports与exports是CommonJS的规范 export与export default是es6规范 require 是 AMD规范引入方式 import是es6的一个语 ...

  6. Selenium+Java(十一)Selenium窗口切换

    前言: Selenium在当前页面调整到新页面时打开了新的窗口,此时就需要跳转到新的窗口去,需要把窗口进行切换. 获取窗口句柄方法: 获取所有: //获取所有窗口句柄,返回的是set类型 driver ...

  7. 线程锁&信号量&gil

    线程锁 线程锁的主要目的是防止多个线程之间出现同时抢同一个数据,这会造成数据的流失.线程锁的作用类似于进程锁,都是为了数据的安全性 下面,我将用代码来体现进程锁的作用: from threading ...

  8. Eclipse官方下载步骤

    今天整理Eclipse项目时,发现自己的IDE不能用了,不兼容自己的JDK,于是决定去官网下载一个适合的IDE,由于官网全部都是英文,所以不是太容易找到,于是就想着出一篇博客帮助以后的人更好的更快的下 ...

  9. PHP安全之道3:常见漏洞和攻防

    第一篇 SQL注入 安全配置和编程安全并不是万全之法,攻击者往往可以通过对漏洞的试探找到新的突破口,甚至0days. 下面总结以下常见漏洞,在日常开发维护工作中可以留意. *聊聊老朋友:SQL注入漏洞 ...

  10. mysql那些事(6) WHERE条件 字符串的引号

    前言:所谓的坑,两个意思,一个是软件本身的bug,一个是使用者常犯的错误. phper在日常开发中经常和mysql打交道.特别是在没有分层的中小应用中,phper开发要关注sql语句的实现. 入正题, ...