- 经典Builder模式 1) 定义:将一个复杂对象的构建与它的表示分离,使得同样 的构建过程可以创建不同的表示。
- 经典的Builder模式有四个参与者
- Product:被构造的复杂对象
- Builder:抽象接口,用来定义创建Product对象的各个组成部
件的操作。 - ConcreteBuilder:Builder接口的具体实现,可以定义多个,
是实际构建Product对象的类,同时会提供一个返回Product的接
口。 - Director:Builder接口的构造者和使用者。
- 简单代码形式
public class Product {
private String mName;
private int mAge;
public String getmName() {
return mName;
}
public void setmName(String mName) {
this.mName = mName;
}
public int getmAge() {
return mAge;
}
public void setmAge(int mAge) {
this.mAge = mAge;
}
}
public interface Builder {
void buildName();
void buildAge();
Product getProduct();
}
public class ConcreteBuilder implements Builder {
private Product mProduct;
@Override
public void buildName() {
}
@Override
public void buildAge() {
}
@Override
public Product getProduct() {
return mProduct;
}
}
public class Director {
private Builder mBuilder;
public Director(Builder builder) {
mBuilder = builder;
}
public void buildProduct() {
mBuilder.buildName();
mBuilder.buildAge();
}
public Product getProduct() {
return mBuilder.getProduct();
}
}
- 经典的Builder模式重点在于抽象出对象创建的步骤,并通过调
用不同的具体实现从而得到不同的、
- Builder模式的变种(Android Builder模式)
- 变种的Builder模式的目的在于减少对象创建过程中引用的多
个重载构造方法、可选参数和setters过度使用导致的不必要的复
杂性。下面以一个简单对象Person对象创建过程为例子说明,它
具有如下所示的属性,且都是不可变的final的。
public class Person{
private final String mName; //必选
private final int mAge; //必选
private final int mGender; //必选
private final String mAddress; //可选
}
由于已经将属性声明为final,因此必须在构造函数中对属性进行
赋值,由于属性有必选和可选之分,也就是说构造方法需要提供
可以选择忽略可选参数的方式。两种方案如下代码所示:
- 构造方法初始化
public Person(String name,int age,int gender){
this(name,age,gender,"")
}
public Person(String name,int age,int
gender,String address){
mName = name;
mAge = age;
mGender = gender;
mAddress = address;
}
- JavaBeans规范(无参构造方法,提供getters和setters方法)
public class Person {
private String mName;
private int mAge;
private int mGender;
private String mAddress;
public String getmName() {
return mName;
}
public void setmName(String mName) {
this.mName = mName;
}
public int getmAge() {
return mAge;
}
public void setmAge(int mAge) {
this.mAge = mAge;
}
public int getmGender() {
return mGender;
}
public void setmGender(int mGender) {
this.mGender = mGender;
}
public String getmAddress() {
return mAddress;
}
public void setmAddress(String mAddress) {
this.mAddress = mAddress;
}
JavaBeans方案的好处是易于阅读和维护,使用Person只需要创建实例对象,调用setters方法设置必要的属性即可。但这样做存在两个缺点:Person类是可变的;Person类是不连续状态的(只有所有的setters方法被调用后,才是连续状态)。那么怎样才可以具有前面方案的优点,又不存在它们的缺点呢?(变种的Builder模式Android Builder模式)
2) Builder模式的变种(Android Builder模式)
public class Person {
private final String mName;
private final int mAge;
private final int mGender;
private final String mAddre;
private Person(Builder builder) {
mName = builder.mName;
mAge = builder.mAge;
mGender = builder.mGender;
mAddre = builder.mAddre;
}
public int getmAge() {
return mAge;
}
public int getmGender() {
return mGender;
}
public String getmName() {
return mName;
}
public String getmAddre() {
return mAddre;
}
public static final class Builder {
private String mName;
private int mAge;
private int mGender;
private String mAddre;
public Builder(String name, int age,
int gender) {
mName = name;
mAge = age;
mGender = gender;
}
public Builder mAddre(String val) {
mAddre = val;
return this;
}
public Person build() {
return new Person(this);
}
}
}
Person类的构造方法是私有的,不可以直接通过new来创建实例Person类是不可变的,对属性值只提供getter方法最后,创建一个Person对象
public Person getPerson() {
return new Person.Builder("Wxq", 23, 1)
.mAddre("China")
.build();
}
- Android Studio自动生成变种Builder模式
- 安装好后重启Android Studio,只需要把属性名确定下来,alt键+insert键,选择builder按钮即可(快捷键Alt+Shift+B)。
- Android中使用Builder模式的例子
1)系统对话的使用Builder模式
public void showDialog() {
AlertDialog alertDialog = new AlertDialog.Builder(this)
.setTitle("对话框")
.setMessage("测试")
.setIcon(R.mipmap.ic_launcher)
.create();
alertDialog.show();
}
- ImageLoader使用Builder模式
private void initImageLoader() {
ImageLoaderConfiguration.Builder config = new
ImageLoaderConfiguration.Builder(getContext());
config.threadPriority(Thread.NORM_PRIORITY - 2);
config.denyCacheImageMultipleSizesInMemory();
config.memoryCacheSize(5 * 1024 * 1024);// 5M
config.tasksProcessingOrder(QueueProcessingType.LIFO);
ImageLoader.getInstance().init(config.build());
}