在Android中探祕建造者模式

前言

在Android開發過程當中,我發現不少安卓源代碼裏應用了設計模式,比較經常使用的有適配器模式(各類adapter),建造者模式(Alert Dialog的構建)等等。雖然咱們對大多數設計模式都有所瞭解,可是在應用設計模式的這個方面,感受不少人在這方面有所不足。因此,咱們能夠看看Android源代碼裏面是怎樣實現各類設計模式的,從而能夠加深咱們對設計模式的理解,從而方便咱們之後對它的應用。今天,咱們就來談談設計者模式(Builder Pattern)。設計模式

定義

建造者模式(Builder Pattern)也叫作生成器模式,其定義以下:app

Separate the construction of a complex object from its representation so that the same construction process can create different representions.
將一個複雜對象的構建與它的表示分離,使得一樣的構建過程能夠建立不一樣的表示。

它的意思就是將一個對象和怎麼構建這個對象分離開來,若是你想構建一個對象,你把這個消息告訴構建者,而且將本身對這個對象的各類要求告訴建造者,而後建造者根據這些要求進行搗鼓,而後,你所須要的一個對象就出來了。框架

Android源代碼AlertDialog的實現

咱們先來看下AlertDialog的源代碼(只列出關鍵代碼):ide

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對象,這樣咱們就能夠不停地調用它設置的方法。post

若是咱們想得到這個AlertDialog。咱們就須要調用建造者的create()方法,在create()方法裏面它就會構造出一個Dialog實例,而且將咱們剛纔設置的屬性所有賦給AlertDialog,最後返回AlertDialog的實例。ui

UniversalImageLoader上面建造者的實現

看完了AlertDialog,咱們這邊再看一個實例,那就是Android開源框架UniversalImageLoader的DisplayImageOptions類,下面是它的一些核心代碼:this

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顯得很是的乾淨,功能也至關的簡潔明瞭。設計

最後,若是本文有什麼疏漏的話,還請指正。rest

口號:Make things Interesting!code

相關文章
相關標籤/搜索
本站公眾號
   歡迎關注本站公眾號,獲取更多信息