設(shè)計(jì)模式之建造模式(建造模式實(shí)現(xiàn)消息提示DialogFragment)

一板乙、什么是建造模式

建造者模式:是將一個(gè)復(fù)雜的對(duì)象的構(gòu)建與它的表示分離是偷,使得同樣的構(gòu)建過程可以創(chuàng)建不同的表示。

舉一個(gè)栗子募逞,我有A蛋铆、B、C凡辱、D戒职、E、F六塊積木透乾。我拿過來一個(gè)機(jī)器洪燥,我只需要向機(jī)器中放入積木,機(jī)器就可以根據(jù)我放入的積木生成不同的模型給我乳乌。此中捧韵,模型為“復(fù)雜的對(duì)象”,積木為“表現(xiàn)”汉操,機(jī)器的作用是“構(gòu)建對(duì)象”再来。當(dāng)我構(gòu)建某個(gè)對(duì)象時(shí),我只需要知道它有什么樣的表現(xiàn)磷瘤,而不需要管它是如何構(gòu)建的芒篷。

建造者模式通常包括下面幾個(gè)角色:

1、Builder:給出一個(gè)抽象接口采缚,以規(guī)范產(chǎn)品對(duì)象的各個(gè)組成成分的建造针炉。這個(gè)接口規(guī)定要實(shí)現(xiàn)復(fù)雜對(duì)象的哪些部分的創(chuàng)建,并不涉及具體的對(duì)象部件的創(chuàng)建扳抽。
2篡帕、ConcreteBuilder:實(shí)現(xiàn)Builder接口殖侵,針對(duì)不同的商業(yè)邏輯,具體化復(fù)雜對(duì)象的各部分的創(chuàng)建镰烧。 在建造過程完成后拢军,提供產(chǎn)品的實(shí)例。
3怔鳖、Director:調(diào)用具體建造者來創(chuàng)建復(fù)雜對(duì)象的各個(gè)部分茉唉,在指導(dǎo)者中不涉及具體產(chǎn)品的信息,只負(fù)責(zé)保證對(duì)象各部分完整創(chuàng)建或按某種順序創(chuàng)建结执。
4赌渣、Product:要?jiǎng)?chuàng)建的復(fù)雜對(duì)象。

二昌犹、演示實(shí)例(Android中使用DialogFragment構(gòu)建消息提示框)

在Android應(yīng)用程序中需要給予用戶不同的消息提示框坚芜。如:僅有一個(gè)ok按鈕的信息提示框,含有取消和確認(rèn)的消息選擇框斜姥,有標(biāo)題有內(nèi)容的消息選擇框等等鸿竖。
提示框上所有的元素可以視為它所包含的“表現(xiàn)”,最后展示給用戶的提示框?yàn)椤皬?fù)雜的對(duì)象”铸敏。我們需要做的就是封裝一個(gè)構(gòu)建最終展示給用戶的提示框的類缚忧。

代碼制造中與定義不符之處

忽略了Director角色類的定義,Director角色的作用是將“復(fù)雜對(duì)象”的要組合的“表現(xiàn)”設(shè)置到ConcreteBuilder角色中杈笔。而ConcreteBuilder角色的作用是將接收到的“表現(xiàn)”進(jìn)行建造組合后闪水,提供產(chǎn)品實(shí)例。

二蒙具、演示實(shí)例

實(shí)際代碼內(nèi)容

代碼制造內(nèi)容中使用了DataBing球榆,用DataBing完成Fragment與布局文件間數(shù)據(jù)的雙向綁定。

1禁筏、Product:要?jiǎng)?chuàng)建的復(fù)雜對(duì)象持钉。
代碼塊
public class PromptDialogFragment extends DialogFragment {

    private final static String TAG = "PromptDialogFragment";

    private static final String BUNDLE_KEY_INFO = "BUNDLE_KEY_INFO";
    private static final String BUNDLE_KEY_CANCEL = "BUNDLE_KEY_CANCEL";
    private static final String BUNDLE_KEY_CONFIRM = "BUNDLE_KEY_CONFIRM";
    private static final String BUNDLE_KEY_OK = "BUNDLE_KEY_OK";
    private static final String BUNDLE_KEY_CALLBACK = "BUNDLE_KEY_CALLBACK";

    /**
     * Dialog提示框的默認(rèn)寬度
     */
    private final int DEFAULT_WIDTH = 240;

    @Inject
    DisplayUtil displayUtil;

    FragmentPromptDialogBinding binding;

    public final ObservableField<String> infoValue = new ObservableField<>();
    public final ObservableField<String> cancelValue = new ObservableField<>();
    public final ObservableField<String> confirmValue = new ObservableField<>();
    public final ObservableField<String> okValue = new ObservableField<>();

    private CallBack callBack;

    public static PromptDialogFragment newInstance(){
        PromptDialogFragment fragment = new PromptDialogFragment();
        return fragment;
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        AndroidSupportInjection.inject(this);
        Bundle bundle = getArguments();
        infoValue.set(bundle.getString(BUNDLE_KEY_INFO));
        cancelValue.set(bundle.getString(BUNDLE_KEY_CANCEL));
        confirmValue.set(bundle.getString(BUNDLE_KEY_CONFIRM));
        okValue.set(bundle.getString(BUNDLE_KEY_OK));
        callBack= (CallBack) bundle.getSerializable(BUNDLE_KEY_CALLBACK);
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        //設(shè)置DialogFragment無標(biāo)題
        getDialog().requestWindowFeature(Window.FEATURE_NO_TITLE);
        binding = DataBindingUtil.inflate(inflater, R.layout.fragment_prompt_dialog, container, false);
        binding.setViewModel(this);
        //設(shè)置點(diǎn)擊空白區(qū)域Dialog框不消失
        setCancelable(false);

        return binding.getRoot();
    }

    @Override
    public void onStart() {
        super.onStart();
        initDialogSize();
    }

    /**
     * 初始化Dialog提示框的大小
     */
    private void initDialogSize(){
        Window window = getDialog().getWindow();
        // 一定要設(shè)置Background,如果不設(shè)置篱昔,window屬性設(shè)置無效
        window.setBackgroundDrawable( new ColorDrawable(Color.TRANSPARENT));

        DisplayMetrics dm = new DisplayMetrics();
        getActivity().getWindowManager().getDefaultDisplay().getMetrics( dm );

        WindowManager.LayoutParams params = window.getAttributes();
        params.gravity = Gravity.CENTER;
        // 使用ViewGroup.LayoutParams每强,以便Dialog 寬度充滿整個(gè)屏幕
        params.width =  displayUtil.dip2px(DEFAULT_WIDTH);
        params.height = ViewGroup.LayoutParams.WRAP_CONTENT;
        window.setAttributes(params);
    }

    public void show(FragmentManager manager) {
        super.show(manager, TAG);
    }

    /**
     * 消息框取消按鈕的點(diǎn)擊事件(左邊按鈕)
     * @param view
     */
    public void cancelClick(View view){
        super.dismiss();
        if(callBack!=null){
            callBack.onCancel();
        }
    }

    /**
     * 消息框確認(rèn)按鈕的點(diǎn)擊事件(右邊按鈕)
     * @param view
     */
    public void confirmClick(View view){
        super.dismiss();
        if(callBack!=null){
            callBack.onSuccess();
        }
    }

    /**
     * 消息框OK按鈕的點(diǎn)擊事件(僅有一個(gè)按鈕)
     * @param view
     */
    public void okClick(View view){
        super.dismiss();
        if(callBack!=null){
            callBack.onSuccess();
        }
    }
    /**
     * Dialog提示框按鈕點(diǎn)擊事件回調(diào)接口
     */
    public interface CallBack extends Serializable {
        void onSuccess();
        void onCancel();
    }
}
2、Builder:給出一個(gè)抽象接口州刽,以規(guī)范產(chǎn)品對(duì)象的各個(gè)組成成分的建造空执。這個(gè)接口規(guī)定要實(shí)現(xiàn)復(fù)雜對(duì)象的哪些部分的創(chuàng)建,并不涉及具體的對(duì)象部件的創(chuàng)建穗椅。
代碼塊
   /**
    * 抽象建造辨绊,以規(guī)范產(chǎn)品對(duì)象的各個(gè)組成成分的建造
    */
    public interface PromptDialogBuilder{
        /**
         * 設(shè)置提示框提示信息
         * @param value
         * @return
         */
        PromptDialogBuilder setInfoValue(String value);

        /**
         * 設(shè)置取消按鈕文言(左側(cè)按鈕)
         * @param value
         * @return
         */
        PromptDialogBuilder setCancelValue(String value);

        /**
         * 設(shè)置確認(rèn)按鈕文言(右側(cè)按鈕)
         * @param value
         * @return
         */
        PromptDialogBuilder setConfirmValue(String value);

        /**
         * 設(shè)置按鈕文言(該按鈕與“取消、確認(rèn)按鈕在顯示上互斥”)
         * @param value
         * @return
         */
        PromptDialogBuilder setOKValue(String value);

        /**
         * 設(shè)置按鈕點(diǎn)擊事件的回調(diào)
         * @param callBack
         * @return
         */
        PromptDialogBuilder setCallBack(CallBack callBack);

        /**
         * 提供產(chǎn)品實(shí)例(返回PromptDialogFragment對(duì)象)
         * @return
         */
        PromptDialogFragment build();
    }
3房待、ConcreteBuilder:實(shí)現(xiàn)Builder接口邢羔,針對(duì)不同的商業(yè)邏輯,具體化復(fù)雜對(duì)象的各部分的創(chuàng)建桑孩。 在建造過程完成后拜鹤,提供產(chǎn)品的實(shí)例。
代碼塊
    /**
     * 具體的建造流椒,針對(duì)不同的商業(yè)邏輯敏簿,具體化復(fù)雜對(duì)象的各部分的創(chuàng)建。 在建造過程完成后宣虾,提供產(chǎn)品的實(shí)例惯裕。
     */
    public final static class Builder implements PromptDialogBuilder{

        private String infoValue;
        private String cancelValue = "取消";
        private String confirmValue = "確認(rèn)";
        private String okValue;
        private CallBack callBack;

        private AppCompatActivity activity;

        public <T extends AppCompatActivity>Builder(T activity){
            this.activity=activity;
        }

        @Override
        public Builder setInfoValue(String value) {
            this.infoValue=value;
            return this;
        }

        @Override
        public Builder setCancelValue(String value) {
            this.cancelValue=value;
            return this;
        }

        @Override
        public Builder setConfirmValue(String value) {
            this.confirmValue=value;
            return this;
        }

        @Override
        public Builder setOKValue(String value) {
            this.okValue=value;
            return this;
        }

        @Override
        public Builder setCallBack(CallBack callBack) {
            this.callBack=callBack;
            return this;
        }

        @Override
        public PromptDialogFragment build() {
            PromptDialogFragment fragment = PromptDialogFragment.newInstance();
            Bundle bundle=new Bundle();
            bundle.putString(BUNDLE_KEY_INFO, infoValue);
            bundle.putString(BUNDLE_KEY_CANCEL, cancelValue);
            bundle.putString(BUNDLE_KEY_CONFIRM, confirmValue);
            bundle.putString(BUNDLE_KEY_OK, okValue);
            bundle.putSerializable(BUNDLE_KEY_CALLBACK, callBack);
            fragment.setArguments(bundle);
            fragment.show(activity.getSupportFragmentManager());
            return fragment;
        }

    }
4、Director:調(diào)用具體建造者來創(chuàng)建復(fù)雜對(duì)象的各個(gè)部分绣硝,在指導(dǎo)者中不涉及具體產(chǎn)品的信息蜻势,只負(fù)責(zé)保證對(duì)象各部分完整創(chuàng)建或按某種順序創(chuàng)建。
代碼塊
new PromptDialogFragment.Builder(this).setInfoValue("您已登錄成功鹉胖!").setOKValue("OK").build();
代碼塊
new PromptDialogFragment.Builder(this)
                .setInfoValue("你是否執(zhí)行登錄操作握玛!")
                .setCancelValue("取消")
                .setConfirmValue("確認(rèn)")
                .setCallBack(new PromptDialogFragment.CallBack() {
                    @Override
                    public void onSuccess() {
                        Toast.makeText(activity, "確認(rèn)操作", Toast.LENGTH_LONG).show();
                    }

                    @Override
                    public void onCancel() {
                        Toast.makeText(activity, "取消操作", Toast.LENGTH_LONG).show();
                    }
                }).build();

最后附上布局文件的內(nèi)容

代碼塊
<layout xmlns:android="http://schemas.android.com/apk/res/android">

    <data>
        <import type="android.view.View"/>
        <variable
            name="viewModel"
            type="com..fragment.PromptDialogFragment" />

    </data>

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@drawable/white_round_bg"
        android:paddingTop="20dp">

        <TextView
            android:id="@+id/prompt_info"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginLeft="15dp"
            android:layout_marginRight="15dp"
            android:gravity="center_horizontal"
            android:text="@{viewModel.infoValue}" />

        <View
            android:id="@+id/prompt_lines"
            android:layout_width="match_parent"
            android:layout_height="0.1dp"
            android:layout_below="@+id/prompt_info"
            android:layout_marginTop="15dp"
            android:background="@color/new_title_line_bg" />

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="40dp"
            android:layout_below="@+id/prompt_lines"
            android:visibility="@{viewModel.okValue==null?View.VISIBLE:View.GONE}">

            <TextView
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:gravity="center"
                android:text="@{viewModel.cancelValue}"
                android:onClick="@{viewModel::cancelClick}"/>

            <View
                android:layout_width="0.1dp"
                android:layout_height="match_parent"
                android:layout_below="@+id/prompt_info"
                android:layout_marginBottom="3dp"
                android:layout_marginTop="3dp"
                android:background="@color/new_title_line_bg" />

            <TextView
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:gravity="center"
                android:text="@{viewModel.confirmValue}"
                android:onClick="@{viewModel::confirmClick}"/>
        </LinearLayout>

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="40dp"
            android:layout_below="@+id/prompt_lines"
            android:visibility="@{viewModel.okValue==null?View.GONE:View.VISIBLE}">

            <TextView
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:gravity="center"
                android:text="@{viewModel.okValue}"
                android:onClick="@{viewModel::okClick}"/>
        </LinearLayout>


    </RelativeLayout>
</layout>
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市甫菠,隨后出現(xiàn)的幾起案子挠铲,更是在濱河造成了極大的恐慌,老刑警劉巖寂诱,帶你破解...
    沈念sama閱讀 217,185評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件拂苹,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡痰洒,警方通過查閱死者的電腦和手機(jī)瓢棒,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來丘喻,“玉大人音羞,你說我怎么就攤上這事〔秩” “怎么了嗅绰?”我有些...
    開封第一講書人閱讀 163,524評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)搀继。 經(jīng)常有香客問我窘面,道長(zhǎng),這世上最難降的妖魔是什么叽躯? 我笑而不...
    開封第一講書人閱讀 58,339評(píng)論 1 293
  • 正文 為了忘掉前任财边,我火速辦了婚禮,結(jié)果婚禮上点骑,老公的妹妹穿的比我還像新娘酣难。我一直安慰自己谍夭,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,387評(píng)論 6 391
  • 文/花漫 我一把揭開白布憨募。 她就那樣靜靜地躺著紧索,像睡著了一般。 火紅的嫁衣襯著肌膚如雪菜谣。 梳的紋絲不亂的頭發(fā)上珠漂,一...
    開封第一講書人閱讀 51,287評(píng)論 1 301
  • 那天,我揣著相機(jī)與錄音尾膊,去河邊找鬼媳危。 笑死,一個(gè)胖子當(dāng)著我的面吹牛冈敛,可吹牛的內(nèi)容都是我干的待笑。 我是一名探鬼主播,決...
    沈念sama閱讀 40,130評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼抓谴,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼滋觉!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起齐邦,我...
    開封第一講書人閱讀 38,985評(píng)論 0 275
  • 序言:老撾萬榮一對(duì)情侶失蹤椎侠,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后措拇,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體我纪,經(jīng)...
    沈念sama閱讀 45,420評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,617評(píng)論 3 334
  • 正文 我和宋清朗相戀三年丐吓,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了浅悉。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,779評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡券犁,死狀恐怖术健,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情粘衬,我是刑警寧澤荞估,帶...
    沈念sama閱讀 35,477評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站稚新,受9級(jí)特大地震影響勘伺,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜褂删,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,088評(píng)論 3 328
  • 文/蒙蒙 一飞醉、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧屯阀,春花似錦缅帘、人聲如沸轴术。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽逗栽。三九已至,卻和暖如春铃诬,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背苍凛。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工趣席, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人醇蝴。 一個(gè)月前我還...
    沈念sama閱讀 47,876評(píng)論 2 370
  • 正文 我出身青樓宣肚,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親悠栓。 傳聞我的和親對(duì)象是個(gè)殘疾皇子霉涨,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,700評(píng)論 2 354

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