一板乙、什么是建造模式
建造者模式:是將一個(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>