对象创建模式Builder

前两天听到有同事抱怨有人的代码中使用and属性名(属性值)的方式创建对象,很不方便,还是提供属性的Getter/Setter方法更好些,听到他这样抱怨的时候我还花了点时间给他讲了采用这种方式创建对象的好处——这种对象创建的方式是为了保护对象在创建之后就不允许被更改。同时也想到这么好的设计模式时很值得学习的,且做个记录。

一般对象实例化

一般对象通过构造方法进行实例化,即通过new Object()的方式,在不声明构造方法的情况下,java默认会有无参的构造方法,也可以通过public T(Object ...)的方式创建具有构造参数的构造方法。

私有构造方法的情况

一般情况下,枚举类型应采用私有构造方法的情况,毕竟枚举类型中的枚举值是应在枚举类创建好之后就应指定(不排除其他的需求),那么会将枚举类型的构造方法设为私有,以保证枚举列表不被破坏。

Builder 对象创建模式

什么情况下需要使用到 Builder的方式去构建对象。如果说只是为了去掉过多的Setter方法去为属性赋值,那完全可以公有其属性(即用public修饰),也就是说,Builder方式创建的对象一般是需要对属性保护的对象,一旦对象被创建,其内容将不可变,为了达到该目的,很容易让人想到被保护的属性需私有化,而能够访问其私有属性的Setter方法的只有通过内部类的方式实现,譬如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
/**
* Builder模式创建对象
* @date 2017年12月26日 上午1:04:55
* @author zero
*/
public class Person {
/** 名字(被保护的属性,无Setter方法) */
private String name;
/** 性别(被保护的属性,无Setter方法) */
private String gendar;
/** 年龄(可变的属性) */
private int age;

/** 私有化其构造方法 */
private Person() {}

public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}

public String getName() {
return name;
}

public String getGendar() {
return gendar;
}

/** 创建构造器 */
public static Builder create() {
return new Builder();
}
/** 静态内部类-Builder */
static class Builder {
private Person person = null;
/** 创建Builder的时候创建 Person实例 */
public Builder() {
person = new Person();
}
/** 赋予属性-名字 */
public Builder name(String name) {
person.name = name;
return this;
}
/** 赋予属性-性别 */
public Builder gendar(String gendar) {
person.gendar = gendar;
return this;
}
/** 赋予属性-年龄(冗余,提供方便) */
public Builder age(int age) {
person.age = age;
return this;
}
/** 返回实例化的Person对象 */
public Person build() {
Person target = person;
person = null; // 防止第二次 build,即build一次之后,这个Builder对象就失效了
return target;
}
}
}

Person中namegendar是受保护的属性,即在Person对象实例化之后,这两个属性值不应该被改变,而age是可变的,提供公有的Setter改变其值。Builder模式可以通过一个静态内部类作为工厂的方式访问私有属性,组装私有属性值之后通过build()方法产出对象,并销毁当前”胚胎”,可以类比为鸡蛋里孵出小鸡,一颗鸡蛋只能孵出一只小鸡。

注意

  • 既然是受保护的对象,一般私有化其构造方法
  • 受保护的对象也可以有可变的属性
  • Builder中容许冗余填充可变的属性方法
  • build()只能产出一次