Builder模式是安卓开发中一种常见的设计模式,这里我们简单介绍一下。
Builder的定义
将一个复杂对象的构造与他的表示分离,使得同样的构造过程可以创建不同的表示。
Builder的使用
Builder设计模式的代码长什么样子,先来大致看一下:
new AlertDialog.Builder(this)
.setTitle("the title")
.setMessage("the message")
.setCancelable(true)
.create()
.show();
很优雅有木有,这个链式调用就是Builder一个很明显的特征,可读性非常强。
我们在什么情况下适合用Builder模式呢?
当我们要创建一个类时,并且这个类中有很多属性且有一部分是可选属性,那么这时候我们就可以使用Builder模式。
这里先贴一个使用Builder的一个demo类,如下:
public class Student {
private final String name;
private final String age;
private final String phone;
private final String address;
private Student(Builder builder){
this.name=builder.name;
this.address=builder.address;
this.age=builder.age;
this.phone=builder.phone;
}
public String getName() {
return name;
}
public String getAge() {
return age;
}
public String getPhone() {
return phone;
}
public String getAddress() {
return address;
}
public static class Builder{
private final String name;
private final String age;
private String phone;
private String address;
public Builder(String name, String age) {
this.name = name;
this.age = age;
}
public Builder phone(String phone){
this.phone=phone;
return this;
}
public Builder address(String address){
this.address=address;
return this;
}
public Student build(){
return new Student(this);
}
}
}
使用时:
new Student.Builder("小明", "26")
.phone("183***")
.address("西湖区")
.build();
我们来看上面这个Student类
这个Student类的构造方法设置成了private,说明调用者不能直接创建Student对象。Student类中有一个静态内部类Builder,Student类有四个属性,我们都设置成了final,只提供getter方法。并且在构造方法中对他们进行了初始化。构造方法中只有一个参数就是Builder对象,我们Student对象的创建就在Builder中的build方法中。所以总的来说我们是使用Builder 对象来创建Student对象。
接下来看这个静态内部类Builder
Builder类中的属性和Student是一致的,有几个方法很明显是分别设置几个属性的,这几个方法的返回值都是Builder本身,这是为了链式调用。Builder类的构造方法中有两个参数,说明有两个属性是必传的。其他的参数就可以使用链式调用按需设置了。当属性设置完毕之后就是调用build方法了,在build方法中创建了Student对象。这时我们要创建Student对象的目的也就完成了。
这样来创建对象不仅可读性强,而且build()方法可以明确的告诉别人对象已经创建完毕。特别优雅。
对于这种有可选属性的对象来说用Builder模式来创建对象有很明显的优势。下面是两种传统写法:
1. 需要写很多参数不同的构造方法,想想就恶心。
2. 先利用无参构造方法创建一个对象,再使用setter()方法把需要的参数set进去。这样也有明显的缺点,一个是对象创建没有一个明显的结束标志,有可能会在对象需要的属性还没完全set进去之前就被调用,这就会出现问题了。另一个是这样创建的这个对象就是可变的了,也就是说在我们创建好的基础上继续改变它,给它set新的属性或者删除某个已经set的属性等。
Builder线程安全问题
Builder是非线程安全的,所以要对参数做合法性验证的话必需要在对象创建完成之后再检查。
正确的代码示例是:
public Student build(){
Student stu=new Student(this);
if(stu.getName().equals("二狗")){
throw new IllegalStateException("这里不允许叫二狗");
}
return stu;
}
一定要先创建对象再进行参数验证,因为如果先验证后创建对象的话,创建的对象的时候对象的属性可能已经被其他线程改变了。