【設(shè)計模式】- Builder(構(gòu)建者)模式

簡介

當(dāng)我們在構(gòu)建一個復(fù)雜的對象時记餐,想要把對象的構(gòu)建和表現(xiàn)分離開來驮樊,那么就可以使用Builder模式。比如:構(gòu)建一臺汽車片酝,組成汽車的部件有很多囚衔,像輪胎,發(fā)動機(jī)雕沿,座位等练湿。當(dāng)具備所以的零部件后脆霎,我們組裝好汽車船侧。那么汽車能干什么乙墙,有怎樣的表現(xiàn)深滚,顯然旭从,汽車能夠以一定速度行駛漾肮。那么怎么才能讓汽車行駛呢路星?點(diǎn)火->給油->發(fā)動機(jī)輸出動力等等席镀。這個是汽車能夠行駛起來需要做的榴捡。所以在構(gòu)建復(fù)雜對象過程杈女,為了使構(gòu)建和表現(xiàn)過程分離,那么可以使用Builder模式吊圾。使得構(gòu)建過程和表現(xiàn)過程都可以自由擴(kuò)展达椰。

why

為什么構(gòu)建復(fù)雜對象,要用Builder模式呢街夭?我創(chuàng)建一個對象砰碴,然后向里面設(shè)置屬性不也可以嗎?為什么非要多出一個Builder類來實(shí)現(xiàn)板丽,不是多增加代碼嗎呈枉?

這種想法沒有什么不對,但是從代碼的清晰堵和擴(kuò)展性埃碱,維護(hù)性上看猖辫,其實(shí)還是有很大不同的,可能對于不是非常復(fù)雜的對象砚殿,沒有什么感覺啃憎,當(dāng)你構(gòu)建的對象越來越復(fù)雜,你會發(fā)現(xiàn)它的好處似炎。

其實(shí)很大講設(shè)計模式辛萍,都會列出幾條使用場景悯姊,當(dāng)我不太喜歡,規(guī)則是死的贩毕,其實(shí)我們更應(yīng)該從單一職責(zé)悯许,擴(kuò)展性,可維護(hù)性辉阶,解耦合先壕,封閉性,替換難易等來考慮怎么書寫代碼谆甜。

UML

Builder模式.png

舉例


public class ExtWebAgent {
    private WebSettings mWebSettings;
    private ExtWebViewClient mWebViewClient;
    private ExtWebChromeClient mWebChromeClient;
    private ExtWebView mWebView;
    private Context mContext;
    private IExtJavascriptInterface mJavascriptInterface;
    private IExtWebViewProgress mExtWebViewProgress;
    private String mJifName;
    IExtCallBack mScrollChangeListener;
    private ExtWebAgent(Builder builder, boolean isCache) {this(builder);}
    public ExtWebAgent(Builder builder) {
        mContext = builder.context;
        mWebView = builder.webView;
        mWebChromeClient = builder.webChromeClient;
        mWebViewClient = builder.webViewClient;
        mJavascriptInterface = builder.javascriptInterface;
        mJifName = builder.jifName;
        mWebView.configWebViewClient(mWebViewClient);
        mWebView.configWebChromeClient(mWebChromeClient
                .addExtWebViewProgress(mExtWebViewProgress)
        mWebView.configOnScrollChanged(mScrollChangeListener);
        if (null != mJavascriptInterface) {
            mWebView.configJavascriptInterface(mJavascriptInterface, mJifName);
            mJavascriptInterface.bindWebView(mWebView);
        }
        mWebView.setDownloadListener(ExtWebDownLoadListener.instance());
        mWebSettings = mWebView.getSettings();
    }
    public static Builder builder(Context context, IExtWebCallback callback) {
        return new Builder(context, callback);
    }
    public static class Builder {
        ExtWebViewClient webViewClient;
        ExtWebChromeClient webChromeClient;
        ExtWebView webView;
        Context context;
        IExtJavascriptInterface javascriptInterface;
        String jifName = "native";
        String cacheBuilderId = "";
        Builder(Context context, IExtWebCallback callback) {
            if (!(context instanceof Activity || context instanceof Application))
                throw new IllegalArgumentException("context is not Activity or Application");
            this.context = context;
            webChromeClient = new ExtWebChromeClient(cacheBuilderId);
            javascriptInterface = new ExtJavaScriptInterfaceIml(cacheBuilderId);
            webViewClient = new ExtWebViewClient(cacheBuilderId);
        }
        public Builder setWebViewClient(ExtWebViewClient wvc) {
            webViewClient = null == wvc ? webViewClient : wvc;
            return this;
        }
        public Builder setChromeClient(ExtWebChromeClient wcc) {
            webChromeClient = null == wcc ? webChromeClient : wcc;
            return this;
        }
        public Builder addJavascriptInterface(IExtJavascriptInterface jif) {
            addJavascriptInterface(jif, jifName);
            return this;
        }
        public Builder addJavascriptInterface(IExtJavascriptInterface jif, String jifName) {
            this.jifName = TextUtils.isEmpty(jifName) ? this.jifName : jifName;
            javascriptInterface = null == jif ? javascriptInterface : jif;
            return this;
        }
        public Builder bindActAndFrag(String key, IExtWebCallback callback) {
            if (null == callback) {
                throw new IllegalArgumentException("callback is null");
            }
            ExtWebViewCallbackManager.instance().bindActAndFrag(key, callback);
            return this;
        }
        public Builder setWebView(ExtWebView wv) {
            webView = wv;
            context = wv.getContext();
            return this;
        }
        public ExtWebAgent build() {
            return new ExtWebAgent(this);
        }
    }
}

源碼中的Builder模式

AlertDialog.Builder就是典型的Builder模式垃僚。這里不貼代碼了,來個UML圖规辱。


Builder模式 - AlertDialog.png

AlertDialog.Builder負(fù)責(zé)組裝谆棺,構(gòu)建。AlertDialog持有AlertController對象按摘,Dialog相關(guān)的操作包券,UI的更新都可以通過它來控制纫谅,這樣相當(dāng)于把Dialog的具體表現(xiàn)抽離出來炫贤,AlertDialog繼承于Dialog,里面負(fù)責(zé)一些事件付秕,狀態(tài)等任務(wù)兰珍。

常用的第三方框架

像Retrofit,okhttp等里面都用到的Builder模式询吴,其用法和上面舉例的一樣掠河。這個模式暫時沒有想到其它變種寫法。

自己的一點(diǎn)理解

其實(shí)Builder模式猛计,簡單點(diǎn)描述就是一個具體對象里面包含了一個用于收集構(gòu)建對象所需要的材料唠摹,當(dāng)收集好后,將其組裝起來奉瘤,形成具有一定表現(xiàn)的對象勾拉。至于這個對象怎樣表現(xiàn)出具有的功能,那么就是對象自己實(shí)現(xiàn)了盗温。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末藕赞,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子卖局,更是在濱河造成了極大的恐慌斧蜕,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,539評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件砚偶,死亡現(xiàn)場離奇詭異批销,居然都是意外死亡洒闸,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,594評論 3 396
  • 文/潘曉璐 我一進(jìn)店門均芽,熙熙樓的掌柜王于貴愁眉苦臉地迎上來顷蟀,“玉大人,你說我怎么就攤上這事骡技∶觯” “怎么了?”我有些...
    開封第一講書人閱讀 165,871評論 0 356
  • 文/不壞的土叔 我叫張陵布朦,是天一觀的道長囤萤。 經(jīng)常有香客問我,道長是趴,這世上最難降的妖魔是什么涛舍? 我笑而不...
    開封第一講書人閱讀 58,963評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮唆途,結(jié)果婚禮上富雅,老公的妹妹穿的比我還像新娘。我一直安慰自己肛搬,他們只是感情好没佑,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,984評論 6 393
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著温赔,像睡著了一般蛤奢。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上陶贼,一...
    開封第一講書人閱讀 51,763評論 1 307
  • 那天啤贩,我揣著相機(jī)與錄音,去河邊找鬼拜秧。 笑死痹屹,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的枉氮。 我是一名探鬼主播志衍,決...
    沈念sama閱讀 40,468評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼嘲恍!你這毒婦竟也來了足画?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤佃牛,失蹤者是張志新(化名)和其女友劉穎淹辞,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體俘侠,經(jīng)...
    沈念sama閱讀 45,850評論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡象缀,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,002評論 3 338
  • 正文 我和宋清朗相戀三年蔬将,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片央星。...
    茶點(diǎn)故事閱讀 40,144評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡霞怀,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出莉给,到底是詐尸還是另有隱情毙石,我是刑警寧澤,帶...
    沈念sama閱讀 35,823評論 5 346
  • 正文 年R本政府宣布颓遏,位于F島的核電站徐矩,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏叁幢。R本人自食惡果不足惜滤灯,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,483評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望曼玩。 院中可真熱鬧鳞骤,春花似錦、人聲如沸黍判。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,026評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽样悟。三九已至拂募,卻和暖如春庭猩,著一層夾襖步出監(jiān)牢的瞬間窟她,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,150評論 1 272
  • 我被黑心中介騙來泰國打工蔼水, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留震糖,地道東北人。 一個月前我還...
    沈念sama閱讀 48,415評論 3 373
  • 正文 我出身青樓趴腋,卻偏偏與公主長得像吊说,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子优炬,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,092評論 2 355

推薦閱讀更多精彩內(nèi)容