Android設計模式--建造者模式,android設計模式--
回頭看自己寫的東西,在關於Android自訂控制項時,寫的代碼適用性比較高,但是看上去沒有什麼技術含量,所以在學習設計模式的時候,想想有些東西是否能夠改進,比如說:
自訂Dialog是Android應用必須的,系統的控制項實在是太難看了;
在構建中,完全是,new完對象之後,需要什麼構建什麼,這樣寫沒有問題,可讀性也還行,就是看上去不咋的。
以下是小部分程式碼片段:
package com.example.demo.Builder;/** * * @author qubian * @data 2015年6月10日 * @email naibbian@163.com * */public class BuilderDialog extends Dialog implements View.OnClickListener {private Context mContext;private View view;private View lineView;private TextView titleTv;private TextView contentTv;private Button sureBtn;private Button cancelBtn;private String sureTitle;private String cancelTitle;private String title;private String content;private boolean sureVisible = true;private boolean cancelVisible = true;private View.OnClickListener sureListener;private View.OnClickListener cancelListener;public BuilderDialog(Context context, String title, String content) {super(context, R.style.base_dialog_style);this.mContext = context;this.title = title;this.content = content;view = LayoutInflater.from(mContext).inflate(R.layout.dialog_normal,null);addContentView(view, Utils.getDialogLayoutParams(mContext));}public void setSureTitle(String title) {sureTitle = title;}public void setCancelTitle(String title) {cancelTitle = title;}public void setCancelVisible(boolean visible) {cancelVisible = visible;}public void setSureListener(View.OnClickListener listener) {if (listener != null) {sureListener = listener;}}public void setCancelListener(View.OnClickListener listener) {}/** * 是否可以返回 * * @param canBack */public void setCanBack(boolean canBack) {} //初始化private void initView() {lineView = view.findViewById(R.id.line_view);titleTv = (TextView) view.findViewById(R.id.title_tv);contentTv = (TextView) view.findViewById(R.id.content_tv);contentTv.setText((content.replace("\\r","\r").replace("\\n", "\n")));sureBtn = (Button) view.findViewById(R.id.sure_btn);cancelBtn = (Button) view.findViewById(R.id.cancel_btn);}@Overridepublic void show() {initView();titleTv.setText(title);if (sureVisible) {if (sureListener == null) {sureBtn.setOnClickListener(this);} else {sureBtn.setOnClickListener(sureListener);}if (sureTitle != null) {sureBtn.setText(sureTitle);}} else {sureBtn.setVisibility(View.GONE);}if (cancelVisible) {} else {}super.show();}@Overridepublic void onClick(View v) {if (v.getId() == sureBtn.getId()) {this.cancel();} else if (v.getId() == cancelBtn.getId()) {this.cancel();}}}
使用,和適用都沒問題,並且邏輯也比較簡單,那麼如何最佳化呢?
言歸正傳:
建造者模式
1、定義:
將一個複雜的構建與其表示分離,使得相同的構建有了不同的表示。
2、目的:
建造者模式是講複雜的內部構建封裝在內部,對於其他外部成員來說,只需要傳遞構建者和構建工具,便可以得到所需,不需要關心如何構建,以及內部構建過程。
3、使用:
3.1、在構建的過程中,允許不同的構建過程,產生不同表示的構建對象;
3.2、在複雜的對象時,其複雜的構建演算法應當獨立於對象的組成部分,或者是獨立於裝配方式時;
4、一個簡單的demo:
核心:抽象建造者,具體建造者,實體類
package com.example.demo.Builder;import android.util.Log;/** * 建造者模式 * @author qubian * @data 2015年6月10日 * @email naibbian@163.com * */public class Product {Builder mBuilder ;public Builder getBuilder(){if (mBuilder==null) {mBuilder = new ProductBuilder();}return mBuilder;}/** * 抽象建造者 * @author qubian * @data 2015年6月10日 * @email naibbian@163.com * */public interface Builder{public Builder buildPart1();public Builder buildPart2();public Product getProduct();}/** * 具體的建造者 * @author qubian * @data 2015年6月10日 * @email naibbian@163.com * */public class ProductBuilder implements Builder{private static final String TAG= "ProductBuilder";Product mProduct = new Product();@Overridepublic Builder buildPart1() {Log.i(TAG, "buildPart1");return this;}@Overridepublic Builder buildPart2() {Log.i(TAG, "buildPart2");return this;}@Overridepublic Product getProduct() {return mProduct;}}}
使用:
package com.example.demo.Builder;/** * 使用 * @author qubian * @data 2015年6月10日 * @email naibbian@163.com * */public class UseProduct {public void use(){Product p = new Product().getBuilder().buildPart1().buildPart2().getProduct();}}
5、在Android的源碼中,建造者模式,肯定是必不可少的;
其中最為代表的就是AlertDialog,在其構建過程中,便是構建與表示分離。其內部的Builder便是他的構建者。
public class AlertDialog extends Dialog implements DialogInterface { private AlertController mAlert; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mAlert.installContent(); } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (mAlert.onKeyDown(keyCode, event)) return true; return super.onKeyDown(keyCode, event); } @Override public boolean onKeyUp(int keyCode, KeyEvent event) { if (mAlert.onKeyUp(keyCode, event)) return true; return super.onKeyUp(keyCode, event); } public static class Builder { private final AlertController.AlertParams P; private int mTheme; /** * Constructor using a context for this builder and the {@link AlertDialog} it creates. */ public Builder(Context context) { this(context, resolveDialogTheme(context, 0)); } /** * Set the title displayed in the {@link Dialog}. * * @return This Builder object to allow for chaining of calls to set methods */ public Builder setTitle(CharSequence title) { P.mTitle = title; return this; } /** * Set the message to display using the given resource id. * * @return This Builder object to allow for chaining of calls to set methods */ public Builder setMessage(int messageId) { P.mMessage = P.mContext.getText(messageId); return this; } /** * Set the message to display. * * @return This Builder object to allow for chaining of calls to set methods */ public Builder setMessage(CharSequence message) { P.mMessage = message; return this; } /** * Set the resource id of the {@link Drawable} to be used in the title. * * @return This Builder object to allow for chaining of calls to set methods */ public Builder setIcon(int iconId) { P.mIconId = iconId; return this; } /** * Set a listener to be invoked when the positive button of the dialog is pressed. * @param textId The resource id of the text to display in the positive button * @param listener The {@link DialogInterface.OnClickListener} to use. * * @return This Builder object to allow for chaining of calls to set methods */ public Builder setPositiveButton(int textId, final OnClickListener listener) { P.mPositiveButtonText = P.mContext.getText(textId); P.mPositiveButtonListener = listener; return this; } /** * Set a listener to be invoked when the positive button of the dialog is pressed. * @param text The text to display in the positive button * @param listener The {@link DialogInterface.OnClickListener} to use. * * @return This Builder object to allow for chaining of calls to set methods */ public Builder setPositiveButton(CharSequence text, final OnClickListener listener) { P.mPositiveButtonText = text; P.mPositiveButtonListener = listener; return this; } /** * Set a listener to be invoked when the negative button of the dialog is pressed. * @param textId The resource id of the text to display in the negative button * @param listener The {@link DialogInterface.OnClickListener} to use. * * @return This Builder object to allow for chaining of calls to set methods */ public Builder setNegativeButton(int textId, final OnClickListener listener) { P.mNegativeButtonText = P.mContext.getText(textId); P.mNegativeButtonListener = listener; return this; } /** * Set a listener to be invoked when the negative button of the dialog is pressed. * @param text The text to display in the negative button * @param listener The {@link DialogInterface.OnClickListener} to use. * * @return This Builder object to allow for chaining of calls to set methods */ public Builder setNegativeButton(CharSequence text, final OnClickListener listener) { P.mNegativeButtonText = text; P.mNegativeButtonListener = listener; return this; } /** * Set a listener to be invoked when the neutral button of the dialog is pressed. * @param textId The resource id of the text to display in the neutral button * @param listener The {@link DialogInterface.OnClickListener} to use. * * @return This Builder object to allow for chaining of calls to set methods */ public Builder setNeutralButton(int textId, final OnClickListener listener) { P.mNeutralButtonText = P.mContext.getText(textId); P.mNeutralButtonListener = listener; return this; } /** * Set a custom view to be the contents of the Dialog. If the supplied view is an instance * of a {@link ListView} the light background will be used. * * @param view The view to use as the contents of the Dialog. * * @return This Builder object to allow for chaining of calls to set methods */ public Builder setView(View view) { P.mView = view; P.mViewSpacingSpecified = false; return this; } /** * Creates a {@link AlertDialog} with the arguments supplied to this builder. It does not * {@link Dialog#show()} the dialog. This allows the user to do any extra processing * before displaying the dialog. Use {@link #show()} if you don't have any other processing * to do and want this to be created and displayed. */ 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; } /** * Creates a {@link AlertDialog} with the arguments supplied to this builder and * {@link Dialog#show()}'s the dialog. */ public AlertDialog show() { AlertDialog dialog = create(); dialog.show(); return dialog; } } }
或許是為了其開放性,AlterView也有自己的構建過程,這樣使用AlterView的構建者Builder可以構建視圖,他自己的對象也可以對其本身進行操作。