Android中的設計模式--建造者模式

之前只知道建造者典型例子是AlertDialog,它的基本寫法是

public class AlertDialog extends Dialog implements DialogInterface {
    private AlertController mAlert;

    protected AlertDialog(Context context) {
        this(context, resolveDialogTheme(context, 0), true);
    }

    @Override
    public void setTitle(CharSequence title) {
        super.setTitle(title);
        mAlert.setTitle(title);
    }

    public void setMessage(CharSequence message) {
        mAlert.setMessage(message);
    }

    public static class Builder {
        private final AlertController.AlertParams P;
        private int mTheme;

        public Builder(Context context, int theme) {
            P = new AlertController.AlertParams(new ContextThemeWrapper(
                    context, resolveDialogTheme(context, theme)));
            mTheme = theme;
        }

        public Builder setTitle(int titleId) {
            P.mTitle = P.mContext.getText(titleId);
            return this;
        }

        public Builder setMessage(CharSequence message) {
            P.mMessage = message;
            return this;
        }

        public Builder setOnCancelListener(OnCancelListener onCancelListener) {
            P.mOnCancelListener = onCancelListener;
            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);
            ...
            return dialog;
        }

        public AlertDialog show() {
            AlertDialog dialog = create();
            dialog.show();
            return dialog;
        }
    }
}

簡單說就是把自個兒構造函數變成了保護類型,就不能主動創建了。那麼創建需要一個使用它內部類Builder,給他傳遞AlertDialog標題、提示、點擊監聽等進行設置,然後每個函數都返回Builder好持續設置。設置完create構建AlertDialog並賦予對應設置項。

我納悶爲什麼不直接new,非要搞個Builder創建,基本代碼是需要寫兩遍。

昨兩天寫了一個實現TextWatcher 的MyTextWatcher,編輯框emoji表情限制,或者輸入字數限制。但編輯框需求不同,有的是需要限制表情,有的只是需要限制字數回調剩餘字數,那麼構造函數就如下

public class MyTextWatcher implements TextWatcher {
    private EditText editText;
    private WatcherListener watcherListener;
    private int max_length;     //最大輸入字數
    private boolean forbiddeEmoji;      //是否禁止輸入表情

    //普通輸入框watcher
    public MyTextWatcher(EditText editText){
        super();
        this.editText = editText;
    }

    //限制表情,但無需剩餘字數監聽回調
    public MyTextWatcher(EditText editText, int max_length){
        this(editText, max_length, null);
    }

    /**
     * 輸入法監聽工具類構造函數
     * @param editText      所需要監聽的editText
     * @param max_length       editText限制輸入長度
     * @param watcherListener  剩餘字數監聽回調
     */
    public MyTextWatcher(EditText editText, int max_length, WatcherListener watcherListener){
        this(editText, false, max_length, null);
    }

    /**
     * 輸入法監聽工具類構造函數
     * @param editText      所需要監聽的editText
     * @param forbiddeEmoji     是否禁止輸入表情
     * @param max_length       editText限制輸入長度
     * @param watcherListener
     */
    public MyTextWatcher(EditText editText, boolean forbiddeEmoji, int max_length, WatcherListener watcherListener){
        super();
        this.forbiddeEmoji = forbiddeEmoji;
        this.editText = editText;
        this.max_length = max_length;
        this.watcherListener = watcherListener;
    }
    。。。
}

雖然最後一個構造函數已經可以包含前面的構造函數,但調用不免不想傳過多的無用參數,所以還是寫了前面的參數少的構造函數。

如果參數更多,需要控制的可能性更多的情況時,你會發現需要寫很多的構造函數去包含這些傳參情況,此時你會發現Builder就能很好的解決這個問題。把所有的需求一次性提完,然後再構建。於是便有了下面的代碼

public class MyTextWatcher implements TextWatcher {
    protected EditText editText;
    protected int max_length = -1;      //最大輸入字數
    protected boolean forbiddeEmoji;        //是否禁止輸入表情
    protected WatcherListener watcherListener;

    protected MyTextWatcher(){
        super();
    }
    ...
    public interface WatcherListener{
        void editTextRemainNum(int num);
    }

    public static class Builder{
        private MyTextWatcher watcher;

        public Builder(EditText edit){
            watcher = new MyTextWatcher();
            watcher.editText = edit;
        }

        public Builder setMax_length(int max_length) {
            watcher.max_length = max_length;
            return this;
        }

        public Builder setForbiddeEmoji(boolean forbiddeEmoji) {
            watcher.forbiddeEmoji = forbiddeEmoji;
            return this;
        }

        public Builder setWatcherListener(WatcherListener Listener){
            watcher.watcherListener = Listener;
            return this;
        }

        public MyTextWatcher create(){
            return watcher;
        }
    }
}

MyTextWatcher是proctected所以外部無法直接創建,Builder構造函數寫上了MyTextWatcher必須的設置的editText。雖然Builder早有MyTextWatcher成員,但一直藏着噎着只有create()的時候才吐出來。當然MyTextWatcher類中對watcherListener的回調前需要判空。

tvbrief.addTextChangedListener(new MyTextWatcher.Builder(tvbrief).setForbiddeEmoji(true).setMax_length(MAX_LENGTH).create())

使用時我們這樣便可以了。當然單獨此例還是構造函數傳參來的快。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章