在Android开发过程中,我发现很多安卓源代码里应用了设计模式,比较常用的有适配器模式(各种adapter),建造者模式(Alert Dialog的构建)等等。虽然我们对大多数设计模式都有所了解,但是在应用设计模式的这个方面,感觉很多人在这方面有所不足。所以,我们可以看看Android源代码里面是怎样实现各种设计模式的,从而可以加深我们对设计模式的理解,从而方便我们以后对它的应用。今天,我们就来谈谈设计者模式(Builder Pattern)。
建造者模式(Builder Pattern)也叫做生成器模式,其定义如下:
Separate the construction of a complex object from its representation so that the same construction process can create different representions.
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
它的意思就是将一个对象和怎么构建这个对象分离开来,如果你想构建一个对象,你把这个消息告诉构建者,并且将自己对这个对象的各种要求告诉建造者,然后建造者根据这些要求进行捣鼓,然后,你所需要的一个对象就出来了。
我们先来看下AlertDialog的源代码(只列出关键代码):
public class AlertDialog extends Dialog implements DialogInterface {
...
protected AlertDialog(Context context, int theme) {
this(context, theme, true);
}
AlertDialog(Context context, int theme, boolean createThemeContextWrapper) {
super(context, resolveDialogTheme(context, theme), createThemeContextWrapper);
mWindow.alwaysReadCloseOnTouchAttr();
mAlert = new AlertController(getContext(), this, getWindow());
}
protected AlertDialog(Context context, boolean cancelable, OnCancelListener cancelListener) {
super(context, resolveDialogTheme(context, 0));
mWindow.alwaysReadCloseOnTouchAttr();
setCancelable(cancelable);
setOnCancelListener(cancelListener);
mAlert = new AlertController(context, this, getWindow());
}
public static class Builder {
private final AlertController.AlertParams P;
private int mTheme;
public Builder(Context context) {
this(context, resolveDialogTheme(context, 0));
}
public Builder(Context context, int theme) {
P = new AlertController.AlertParams(new ContextThemeWrapper(
context, resolveDialogTheme(context, theme)));
mTheme = theme;
}
public Builder setMessage(CharSequence message) {
P.mMessage = message;
return this;
}
public AlertDialog create() {
final AlertDialog dialog = new AlertDialog(P.mContext, mTheme, false);
P.apply(dialog.mAlert);
dialog.setCancelable(P.mCancelable);
if (P.mCancelable) {
dialog.setCanceledOnTouchOutside(true);
}
dialog.setOnCancelListener(P.mOnCancelListener);
dialog.setOnDismissListener(P.mOnDismissListener);
if (P.mOnKeyListener != null) {
dialog.setOnKeyListener(P.mOnKeyListener);
}
return dialog;
}
...
}
}
从上面我们可以清楚地看到:AlertDialog的Build是一个静态内部类(在有些情况下,我们会单独定义一个Build抽象类,然后用具体类来继承它,实现具体的功能)。我们对AlertDialog设置的属性会暂时保存在Build类的成员变量P(AlertController.AlertParams)中。同时,我们注意到我们设置的属性,它都回返回本身的AlertBuild对象,这样我们就可以不停地调用它设置的方法。
如果我们想获得这个AlertDialog。我们就需要调用建造者的create()方法,在create()方法里面它就会构造出一个Dialog实例,并且将我们刚才设置的属性全部赋给AlertDialog,最后返回AlertDialog的实例。
看完了AlertDialog,我们这边再看一个实例,那就是Android开源框架UniversalImageLoader的DisplayImageOptions类,下面是它的一些核心代码:
public final class DisplayImageOptions {
private final int imageResOnLoading;
private final int imageResForEmptyUri;
private final int imageResOnFail;
private final Drawable imageOnLoading;
private final Drawable imageForEmptyUri;
private final Drawable imageOnFail;
private final boolean resetViewBeforeLoading;
private final boolean cacheInMemory;
private final boolean cacheOnDisk;
private final ImageScaleType imageScaleType;
private final Options decodingOptions;
private final int delayBeforeLoading;
private final boolean considerExifParams;
private final Object extraForDownloader;
private final BitmapProcessor preProcessor;
private final BitmapProcessor postProcessor;
private final BitmapDisplayer displayer;
private final Handler handler;
private final boolean isSyncLoading;
private DisplayImageOptions(Builder builder) {
imageResOnLoading = builder.imageResOnLoading;
imageResForEmptyUri = builder.imageResForEmptyUri;
imageResOnFail = builder.imageResOnFail;
imageOnLoading = builder.imageOnLoading;
imageForEmptyUri = builder.imageForEmptyUri;
imageOnFail = builder.imageOnFail;
resetViewBeforeLoading = builder.resetViewBeforeLoading;
cacheInMemory = builder.cacheInMemory;
cacheOnDisk = builder.cacheOnDisk;
imageScaleType = builder.imageScaleType;
decodingOptions = builder.decodingOptions;
delayBeforeLoading = builder.delayBeforeLoading;
considerExifParams = builder.considerExifParams;
extraForDownloader = builder.extraForDownloader;
preProcessor = builder.preProcessor;
postProcessor = builder.postProcessor;
displayer = builder.displayer;
handler = builder.handler;
isSyncLoading = builder.isSyncLoading;
}
...
public static class Builder {
private int imageResOnLoading = 0;
private int imageResForEmptyUri = 0;
private int imageResOnFail = 0;
private Drawable imageOnLoading = null;
private Drawable imageForEmptyUri = null;
private Drawable imageOnFail = null;
private boolean resetViewBeforeLoading = false;
private boolean cacheInMemory = false;
private boolean cacheOnDisk = false;
private ImageScaleType imageScaleType = ImageScaleType.IN_SAMPLE_POWER_OF_2;
private Options decodingOptions = new Options();
private int delayBeforeLoading = 0;
private boolean considerExifParams = false;
private Object extraForDownloader = null;
private BitmapProcessor preProcessor = null;
private BitmapProcessor postProcessor = null;
private BitmapDisplayer displayer = DefaultConfigurationFactory.createBitmapDisplayer();
private Handler handler = null;
private boolean isSyncLoading = false;
public Builder() {
decodingOptions.inPurgeable = true;
decodingOptions.inInputShareable = true;
}
/**
* Stub image will be displayed in {@link com.nostra13.universalimageloader.core.imageaware.ImageAware
* image aware view} during image loading
*
* @param imageRes Stub image resource
* @deprecated Use {@link #showImageOnLoading(int)} instead
*/
@Deprecated
public Builder showStubImage(int imageRes) {
imageResOnLoading = imageRes;
return this;
}
/**
* Incoming image will be displayed in {@link com.nostra13.universalimageloader.core.imageaware.ImageAware
* image aware view} during image loading
*
* @param imageRes Image resource
*/
public Builder showImageOnLoading(int imageRes) {
imageResOnLoading = imageRes;
return this;
}
/** Builds configured {@link DisplayImageOptions} object */
public DisplayImageOptions build() {
return new DisplayImageOptions(this);
}
...
}
}
它比AlertDialog实现更为简单一点,直接将属性定义在Builder的成员变量中,然后将Builder对象返回给DisplayImageOptions中直接进行赋值,这样做的话,将初始化对象的复杂逻辑全部交给了Builder类,而使我们需要的DisplayImageOptions显得非常的干净,功能也相当的简洁明了。
最后,如果本文有什么疏漏的话,还请指正。
口号:Make things Interesting!