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