当我在学习领域驱动设计(DDD)以及Effective Java的时候,发现构造者模式非常有用。从阅读方式及性能原因分析如下:
第一:在领域驱动设计中,很多时候需要给领域对象赋值,那么当一个领域对象的属性域(Field字段)内容较多,那么赋值的时候,怎么达到轻松易读,意思表达明确,语句简单?
第二:怎么通过对对象的赋值就能知道对象有哪些属性,以及对应属性的名称和含义?
构造者模式能很好的解决上面问题,回到构造者模式定义上:
构造柱模式能将复杂对象的构造过程与其表示分开,以便同样的构造过程可以创建不同的对象呈现,并且这种设计模式能带来一个副作用:我们可以避免与构造函数构造一个参数较多对象相关的错误,考虑下面实例:
public class Employee {
private int id;
private String name;
private String department;
private String address;
private String phone;
private String mobile;
public Employee(String name, String deptt, String address,
String phone, String mobile) {
super();
this.id = generateId();
this.name = name;
this.deptt = deptt;
this.address = address;
this.phone = phone;
this.mobile = mobile;
}
private int generateId(){
int id = 0; //Generate a unique id here with some mechanism
return id;
}
}
你能发现问题吗??
这个Employee的构造函数需要开发者传入name、deptt、address等,并且按照特定的顺序,并且所有的参数都是String类型,所以在传入参数时候,开发者还必须记住或者查找文档中所有参数的意义。想象一下当有超过10个参数的情况。这在这种情况下非常麻烦。
我们如何让使用这个类的开发人员更轻松?一种方式可能是为每个属性提供默认的构造函数和setter方法。我用这种方法看到了一些问题,即:
- 如果我的类不应该有默认的构造函数,即我们无法想象没有姓名,部门,地址,电话或移动设备的员工。一个参数可能是我们有一个具有强制属性的构造函数。如果强制性属性列表本身太长,我们还是需要知道所以属性含义,问题依然是属性太多而不知具体含义。但是,如果强制性参数的数量不是太大,那么我们可以使用这种方法。
- 如果我们使用setter,有时候我们创建了员工对象,但在逻辑意义上并不完整,即我们仍在设置属性。当有多个线程试图访问该对象时,该对象的不一致状态可能会导致问题。
接下来我们尝试用构造者模式来解决:
然而,在我们看到它之前,在实施过程中需要注意几点。
- Employee类的构造函数必须是私有的,确保没有人可以使用有问题的构造函数创建对象,也阻止了开发者直接用构造函数创建对象。
- Builder类是一个内联类。为什么是内联类?因为我们在原Employee类中不提供公共的setter方法,当时构造器却需要访问Employee的私有属性。所以Builder只能是Employee的内联类。
public class Employee {
private int id;
private String name;
private String department;
private String address;
private String phone;
private String mobile;
private Employee(String name, String deptt, String address,
String phone, String mobile) {
super();
this.id = generateId();
this.name = name;
this.department = deptt;
this.address = address;
this.phone = phone;
this.mobile = mobile;
}
private int generateId() {
//Generate an id with some mechanism
int id = 0;
return id;
}
@Override
public String toString() {
return "Employee [id=" + id + ", name=" + name + ", department=" +
department + ", address=" + address + ", phone=" + phone + ", mobile=" + mobile + "]";
}
static public class Builder {
private int id;
private String name;
private String department;
private String address;
private String phone;
private String mobile;
public Builder() {}
public Builder name(String name) {
this.name = name;
return this;
}
public Builder department(String deptt) {
this.department = deptt;
return this;
}
public Builder address(String address) {
this.address = address;
return this;
}
public Employee build() {
Employee emp = new Employee(name, department, address, phone, mobile);
return emp;
}
}
}
其中注意:
1、Employee的构造函数是私有的。
2、Builder的类为static的。
调用的写法如下:
public class TestMain {
public static void main(String[] args) {
Employee.Builder builder = new Employee.Builder();
Employee emp = builder.address("my address").department("my deptt").name("my name").build();
System.out.println("Employee created is " + emp);
}
}