回头看自己写的东西,在关于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); } @Override public 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(); } @Override public 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(); @Override public Builder buildPart1() { Log.i(TAG, "buildPart1"); return this; } @Override public Builder buildPart2() { Log.i(TAG, "buildPart2"); return this; } @Override public 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可以构建视图,他自己的对象也可以对其本身进行操作。