场景 (1)构造一个复杂的对象,很多的属性,有些属性构造的时候需要做一些校验,格式转换
1.常规
package com.example.demo.pattern.builder;/*** @author chenchao* @date 2021/11/9*/public class WithoutBuilderPatternDemo {public static void main(String[] args) {// 构造这个复杂的product对象Product product = new Product();// 设置field1属性System.out.println("在设置field1之前进行复杂的校验逻辑");product.setField1("值1");// 设置field2属性System.out.println("在设置field2之前进行复杂的数据格式转化逻辑");product.setField2("值2");// 设置field3属性System.out.println("在设置field3之前进行复杂的数据处理逻辑,跟其他对象的数据进行关联");product.setField3("值3");// 上面是简化的一个逻辑,实际上对于一些有几十个字段,甚至是上百个字段的复杂对象的构建// 上面那段代码会极度膨胀,非常复杂// 一个是说,大量代码堆积在一起,维护性非常差,可读性非常差,一坨代码,跟屎一样,读不懂,没法改// 另外一个,就是说,这段逻辑,如果在多个地方都有使用的话,一旦这段逻辑出现了一些变化,那么可能就需要// 在多个地方修改这一大坨跟屎一样的代码// 把不同的构造的步骤,抽取成某一个方法}public static class Product {private String field1;private String field2;private String field3;public String getField1() {return field1;}public void setField1(String field1) {this.field1 = field1;}public String getField2() {return field2;}public void setField2(String field2) {this.field2 = field2;}public String getField3() {return field3;}public void setField3(String field3) {this.field3 = field3;}}}
2.构造器模式
package com.example.demo.pattern.builder;/*** @author chenchao* @date 2021/11/9*/public class BuilderPatternDemo {public static void main(String[] args) {Director director = new Director(new ConcreteBuilder());Product product = director.build("值1", "值2", "值3");System.out.println(product);// 好处1:通过builder接口将复杂构建步骤拆分成了多个部分,代码逻辑清晰,维护性和扩展性都很好// 好处2:将对象构建的过程,封装在了director里面,director来基于builder进行构建,构建逻辑修改,不需要修改很多地方// 好处3:相对于工厂,有一个很好的抽象设计,director和builder}public static class Product {private String field1;private String field2;private String field3;public String getField1() {return field1;}public void setField1(String field1) {this.field1 = field1;}public String getField2() {return field2;}public void setField2(String field2) {this.field2 = field2;}public String getField3() {return field3;}public void setField3(String field3) {this.field3 = field3;}@Overridepublic String toString() {return "Product [field1=" + field1 + ", field2=" + field2 + ", field3=" + field3 + "]";}}public interface Builder {void field1(String value);void field2(String value);void field3(String value);Product create();}public static class ConcreteBuilder implements Builder {private Product product = new Product();@Overridepublic void field1(String value) {System.out.println("在设置field1之前进行复杂的校验逻辑");product.setField1(value);}@Overridepublic void field2(String value) {System.out.println("在设置field2之前进行复杂的数据格式转化逻辑");product.setField2(value);}@Overridepublic void field3(String value) {System.out.println("在设置field3之前进行复杂的数据处理逻辑,跟其他对象的数据进行关联");product.setField3(value);}@Overridepublic Product create() {return product;}}/*** director是面向builder的接口,来编程的* director可以复杂控制构建的一个步骤,具体的每个步骤的逻辑封装在具体的builder类中* 如果我们此时要更换一整套的构建逻辑,可以再搞一个新的builder类就可以了* 但是我们的整个构建步骤是没有任何改变的** 如果整个构建步骤变化了,但是对构建的逻辑是没有影响的** @author chenchao**/public static class Director {private Builder builder;public Director(Builder builder) {this.builder = builder;}public Product build(String field1, String field2, String field3) {builder.field1(field1);builder.field2(field2);builder.field3(field3);return builder.create();}}}
3.升级 搭配工厂模式
package com.example.demo.pattern.builder;/*** @author chenchao* @date 2021/11/9*/public class OptimizedBuilderPatternDemo {public static void main(String[] args) {Product product = new ConcreteBuilder().field1("值1").field2("值2").field3("值3").create();System.out.println(product);// 现在基本上流行的一些开源框架,构造器模式的运用,一般都是上面这种变种模式}public static class Product {private String field1;private String field2;private String field3;public String getField1() {return field1;}public void setField1(String field1) {this.field1 = field1;}public String getField2() {return field2;}public void setField2(String field2) {this.field2 = field2;}public String getField3() {return field3;}public void setField3(String field3) {this.field3 = field3;}@Overridepublic String toString() {return "Product [field1=" + field1 + ", field2=" + field2 + ", field3=" + field3 + "]";}}public interface Builder {Builder field1(String value);Builder field2(String value);Builder field3(String value);Product create();}public static class ConcreteBuilder implements Builder {private Product product = new Product();public Builder field1(String value) {System.out.println("在设置field1之前进行复杂的校验逻辑");product.setField1(value);return this;}public Builder field2(String value) {System.out.println("在设置field2之前进行复杂的数据格式转化逻辑");product.setField2(value);return this;}public Builder field3(String value) {System.out.println("在设置field3之前进行复杂的数据处理逻辑,跟其他对象的数据进行关联");product.setField3(value);return this;}public Product create() {return product;}}}
4.说明
构造器是一种非常棒,非常实用,非常常用的设计模式
常见于在构建一个复杂的对象,或者是构建一个复杂的表达式的时候,在开源框架中有大量广泛的运用
给大家举个例子,Mockito框架中,when().thenReturn()之类的,其实就是构造器模式的一种,通过多个连续的方法完成一个模拟对象的构建;还有就是spring test框架汇总,MvcMock对象,也是通过thenExpected()等多个连续的方法,完成一个mvc测试对象的构建。
用构造器模式的最大好处是啥?复杂对象的构建过程太复杂了,里面可能包含一些业务逻辑,比如值检查,格式转换之类的。如果每个客户端都自己手动去完成构建的话,那么大量的冗余代码是一个;另外一个,如果我们要改变对象的构建过程的实现,可以就在构造器中一个地方修改即可,对于调用方完全透明;最后,如果我们要完全替换掉以前的builder实现的话,那么完全可以在工厂里替换一个实现,还跟简单工厂模式结合起来使用了
