转载请注明出处:http://blog.csdn.net/tyhj_sf/article/details/51724383
本文为分析Android API源码用到的设计模式系列文章之一,专门分析Builder Pattern(建造者模式),如果想了解其他若干种设计模式,可阅读作者的系列文章。
下图列表为23种经典设计模式分类,本系列文章将结合Android源码详细分析。
按照Gof的说法:Builder Pattern是将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示。 [构建与表示分离,同构建不同表示]
与抽象工厂的区别:在建造者模式里,有个指导者,由指导者来管理建造者,用户是与指导者联系的,指导者联系建造者最后得到产品。即建造模式可以强制实行一种分步骤进行的建造过程。
Builder模式是将复杂的内部创建封装在内部,对于外部调用的人来说,只需要传入Builder和Builder方法,对于内部是如何建造成成品的,调用者无需关心。
举个简单的例子,如汽车,有很多部件,车轮,方向盘,发动机还有各种小零件等等,部件很多,但远不止这些,如何将这些部件装配成一部汽车,这个装配过程也很复杂(需要很好的组装技术), Builder模式就是为了将部件和组装分开。
builder:给出一个抽象接口,以规范产品对象的各个组成成分的建造。这个接口规定要实现复杂对象的哪些部分的创建,并不涉及具体的对象部件的创建。
ConcreteBuilder:实现Builder接口,针对不同的商业逻辑,具体化复杂对象的各部分的创建。 在建造过程完成后,提供产品的实例。
Director:调用具体建造者来创建复杂对象的各个部分,在指导者中不涉及具体产品的信息,只负责保证对象各部分完整创建或按某种顺序创建。
Product:要创建的复杂对象。
我们根据建造者模式的结构图写一个简单的实例。
类及接口定义:
public interface Builder {
void buildPartA();
void buildPartB();
void buildPartC();
Product getResult();
}
//具体建造工具
public class ConcreteBuilder implements Builder {
Part partA, partB, partC;
public void buildPartA() {
//这里是具体如何构建partA的代码
};
public void buildPartB() {
//这里是具体如何构建partB的代码
};
public void buildPartC() {
//这里是具体如何构建partB的代码
};
public Product getResult() {
//返回最后组装成品结果
};
}
//建造者
public class Director {
private Builder builder;
public Director( Builder builder ) {
this.builder = builder;
}
public void construct() {
builder.buildPartA();
builder.buildPartB();
builder.buildPartC();
}
}
public interface Product { }
public interface Part { }
调用过程:
ConcreteBuilder builder = new ConcreteBuilder();
Director director = new Director( builder );
director.construct();
Product product = builder.getResult();
特别推荐书《Effective Java》中介绍的Builder Pattern用法:
// Builder Pattern
public class NutritionFacts {
private final int servingSize;
private final int servings;
private final int calories;
private final int fat;
private final int sodium;
private final int carbohydrate;
public static class Builder {
// Required parameters
private final int servingSize;
private final int servings;
// Optional parameters - initialized to default values
private int calories = 0;
private int fat = 0;
private int carbohydrate = 0;
private int sodium = 0;
public Builder(int servingSize, int servings) {
this.servingSize = servingSize;
this.servings = servings;
}
public Builder calories(int val){
calories = val;
return this;
}
public Builder fat(int val){
fat = val;
return this;
}
public Builder carbohydrate(int val){
carbohydrate = val;
return this;
}
public Builder sodium(int val){
sodium = val;
return this;
}
public NutritionFacts build() {
return new NutritionFacts(this);
}
}
private NutritionFacts(Builder builder) {
servingSize = builder.servingSize;
servings = builder.servings;
calories = builder.calories;
fat = builder.fat;
sodium = builder.sodium;
carbohydrate = builder.carbohydrate;
}
}
对象的构造过程:
NutritionFactscocaCola = new NutritionFacts.Builder(240, 8).
calories(100).sodium(35).carbohydrate(27).build();
在Android开发中,AlertDialog的创建过程中就用到了Builder模式。官方文档中给出的创建AlertDialog对象的示例代码如下:
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
// Add the buttons
builder.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
// User clicked OK button
}
});
builder.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
// User cancelled the dialog
}
});
// Set other dialog properties
...
// Create the AlertDialog
AlertDialog dialog = builder.create();
下面我们来看看类AlertDialog和类Builder源码。
1. 我们先看看类AlertDialog定义的成员变量及构造方法,代码如下:
public class AlertDialog extends Dialog implements DialogInterface {
private AlertController mAlert;
protected AlertDialog(Context context) {
this(context, resolveDialogTheme(context, 0), true);
}
protected AlertDialog(Context context, int theme) {
this(context, theme, true);
}
AlertDialog(Context context, int theme, boolean createThemeContextWrapper) {
//省略
··········
}
protected AlertDialog(Context context, boolean cancelable, OnCancelListener cancelListener) {
//省略
··········
}
//后面跟省略
·············
·············
}
类AlertDialog的所有组件如title、icon、button、message等都封装在AlertController类中,方便对包含的组件统一设置。类AlertController的源码结构如下图:
AlertController类相当重要,AlertDialog类的大部分getter和setter方法的实现都依赖于这个类的getter和setter方法,见下面的代码例子。
AlertDialog类2个典型getter和setter方法:
public ListView getListView() {
return mAlert.getListView();
}
@Override
public void setTitle(CharSequence title) {
super.setTitle(title);
mAlert.setTitle(title);
}
其中变量mAlert是AlertController类的实例。
另外,
再看看Builder类2个典型setter方法:
public Builder setMessage(CharSequence message) {
P.mMessage = message;
return this;
}
public Builder setIcon(int iconId) {
P.mIconId = iconId;
return this;
}
其中变量P是AlertController类的内部类AlertParams的实例。由类:AlertDialog、AlertController、AlertParams三者的关系可知,对类AlertController、AlertParams的设置表现为对AlertDialog的组件的设置。
而且,上面这段代码中方法的返回值均为this,这使得build过程可以连续进行,像这样:
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
AlertDialog dialog =
builder.setTitle(···) //传入参数均省略
.setMessage(···) //传入参数均省略
.setPositiveButton(···) //传入参数均省略
.setNegativeButton(···) //传入参数均省略
.create();
与前面介绍的Builder模式的一般用法相比,这省去Director类,使得Builder的使用更加简单、灵活。