您的位置:首页 > 其它

设计模式(三)建造者模式

2017-09-19 16:42 155 查看

引出问题:

 

  很多人应该遇到这么一种情况,我需要一个对象,但是这个对象比较复杂,有很多属性,你希望在创建对象的同时初始化这些属性。

  很自然的,你会想到为这些属性创建对应参数的构造器。

  那么问题又来了,如果这些属性,有些时候有,有些时候没有,怎么办呢?

 

 

数据模型:

 

1 @EqualsAndHashCode
2 @Data
3 public class PolicyCommon {
4
5     private String code;
6     private String category;
7     private String name;
8     private String inceptionDate;
9
10     public PolicyCommon() {
11         super();
12     }
13
14     public PolicyCommon(String code, String category, String name) {
15         super();
16         this.code = code;
17         this.category = category;
18         this.name = name;
19     }
20
21 }

 

 

分析:

 

  以上这个模型,一共拥有4个属性,假定 inceptionDate 属性,在创建对象的时候不需要,其他三个属性都可有可无。

  如此一来,初始化的对象可能出现的状态个数为:2^3=8

 

 

传统意义上的解决方案:

 

  通过构造器的设计,可以解决这个问题,有两种方案:

  • 提供无参构造器,优先创建一个空对象,然后依次调用 set 方法。
  • 提供三个参数的构造器,如果某个属性不需要,构造器对应的参数上赋值 null。

 

  以上两种设计,都有各自的问题:

  第一种,问题在于,讲构造对象的动作,拆分成多次,导致对象不是一次性构造完成,在中间步骤中出现对象不一致的情况。

  第二种,问题在于,从代码上看,属性的意义不明显,如果这是一个不需要任何属性的,如:new PolicyCommon(null, "", null),使用者怎么知道第二个参数到底是什么?

 

 

使用建造者模式:

 

  在 《Effective Java》 中,强烈建议在遇到这种复杂的情况时,使用建造者模式来完成创建对象的任务。

  建造者模式(Builder Pattern),也称生成器模式,定义如下:

  将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

  Separate the construction of a complex object from its representation so that the same construction process can create different representation.

 

 

思想:

 

  使用一个静态内部类 Builder,Builder 中持有外部类中,需要动态生成的属性。

  Builder 为每一个属性,提供 set() 方法,但是与通常的set() 方法不同,这些 set() 方法的返回值是 Builder 本身。

  Builder 提供一个 build() 方法,返回类型为外部类。

  外部类中,仅仅提供一个参数为 Builder 对象的构造器,且将其的权限设置为 private,如此一来,构造器的唯一途径就是 build() 方法。

 

 

代码:

 

1 public final class BuilderTest {
2
3     @Test
4     public void test() {
5         PolicyCommon policy1 = new PolicyCommon();
6         policy1.setName("");
7         policy1.setCode("");
8         PolicyCommon policy2 = new PolicyCommon("", null, "");
9         Assert.assertEquals(policy1, policy2);
10         PolicyBuilder policy3 = new PolicyBuilder.Builder().setName("").setCode("").build();
11         PolicyBuilderLombok policy4 = new PolicyBuilderLombok.PolicyBuilderLombokBuilder().name("").code("").build();
12         Assert.assertEquals(policy3.getName(), policy4.getName());
13         Assert.assertEquals(policy3.getCode(), policy4.getCode());
14         Assert.assertEquals(policy3.getCategory(), policy4.getCategory());
15         Assert.assertEquals(policy3.getInceptionDate(), policy4.getInceptionDate());
16     }
17
18 }
JUnit

 

  可以看出,除了名称之外,@Builder 注解调用的方式与自己实现建造者模式,并没有什么不同,如果没有一些特殊的要求,Lombok 的 @Builder 注解,可以成为主流的建造者模式的使用方式。

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: