构建模式实现与研究 - bei1999/work GitHub Wiki
定义
通过组件的装配一步一步完成目的对象的构建过程
场景模拟
- android 系统的AlertDialog 源码分析
- 项目中的实践
实现
- android 系统的AlertDialog 源码分析
/**
* author : lzb
* e-mail :
* time : 2017/12/07
* desc : 主类调用
* version: 1.0
*/
public class Test extends Activity{
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_clock_view);
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setIcon(R.drawable.psts_background_tab);
builder.setMessage("提示");
AlertDialog dialog = builder.create();
dialog.show();
}
}
//AlertDialog 中的Builder 实现为一个静态内部类
public static class Builder {
private final AlertController.AlertParams P;
/**
* Creates a builder for an alert dialog that uses the default alert
* dialog theme.
* <p>
* The default alert dialog theme is defined by
* {@link android.R.attr#alertDialogTheme} within the parent
* {@code context}'s theme.
*
* @param context the parent context
*/
public Builder(Context context) {
this(context, resolveDialogTheme(context, 0));
}
/**
* Creates a builder for an alert dialog that uses an explicit theme
* resource.
* <p>
* The specified theme resource ({@code themeResId}) is applied on top
* of the parent {@code context}'s theme. It may be specified as a
* style resource containing a fully-populated theme, such as
* {@link android.R.style#Theme_Material_Dialog}, to replace all
* attributes in the parent {@code context}'s theme including primary
* and accent colors.
* <p>
* To preserve attributes such as primary and accent colors, the
* {@code themeResId} may instead be specified as an overlay theme such
* as {@link android.R.style#ThemeOverlay_Material_Dialog}. This will
* override only the window attributes necessary to style the alert
* window as a dialog.
* <p>
* Alternatively, the {@code themeResId} may be specified as {@code 0}
* to use the parent {@code context}'s resolved value for
* {@link android.R.attr#alertDialogTheme}.
*
* @param context the parent context
* @param themeResId the resource ID of the theme against which to inflate
* this dialog, or {@code 0} to use the parent
* {@code context}'s default alert dialog theme
*/
public Builder(Context context, int themeResId) {
P = new AlertController.AlertParams(new ContextThemeWrapper(
context, resolveDialogTheme(context, themeResId)));
}
/**
* Returns a {@link Context} with the appropriate theme for dialogs created by this Builder.
* Applications should use this Context for obtaining LayoutInflaters for inflating views
* that will be used in the resulting dialogs, as it will cause views to be inflated with
* the correct theme.
*
* @return A Context for built Dialogs.
*/
public Context getContext() {
return P.mContext;
}
/**
* Set the title using the given resource id.
*
* @return This Builder object to allow for chaining of calls to set methods
*/
public Builder setTitle(@StringRes int titleId) {
P.mTitle = P.mContext.getText(titleId);
return this;
}
/**
* 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;
}
create 方法进行了类实例化构造
/**
* Creates an {@link AlertDialog} with the arguments supplied to this
* builder.
* <p>
* Calling this method does not display the dialog. If no additional
* processing is needed, {@link #show()} may be called instead to both
* create and display the dialog.
*/
public AlertDialog create() {
// Context has already been wrapped with the appropriate theme.
final AlertDialog dialog = new AlertDialog(P.mContext, 0, 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;
}
小结
AlertDialog类的过程隐藏了类的内部实现细节,程序员只需要按照AlertDialog固定的方式去使用Builder设计模式封装的类即可,每一个setXXX()方法,发现统一返回当前对象,通过当前对象去调用另一个setXXX()方法,然后继续调用,这也是为什么使用Builder设计模式的例子,可以支持链式调用。
项目中的实践
/**
* author : lzb
* e-mail :
* time : 2017/12/07
* desc : build 模式封装参数
* version: 1.0
*/
public abstract class Builder {
public abstract Builder setRadius(float radius) ;
public abstract Builder setTextSize(float textSize) ;
public abstract Builder setBackgroundColor(int backgroundColor) ;
public abstract Builder setPadding(float padding) ;
public abstract ClockViewImpl create() ;
}
/**
* author : lzb
* e-mail :
* time : 2017/12/07
* desc : 表盘
* version: 1.0
*/
public abstract class ClockView extends View {
public ClockView(Context context) {
super(context);
}
public ClockView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public abstract void paint(Canvas canvas);
}
package com.bei.test.builder;
import android.content.Context;
import android.graphics.Canvas;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
/**
* author : lzb
* e-mail : [email protected]
* time : 2017/12/07
* desc : 表盘实现类
* version: 1.0
*/
public class ClockViewImpl extends ClockView {
private float mTextSize; //文字大小
public ClockViewImpl(Context context) {
super(context);
}
public ClockViewImpl(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
@Override
public void paint(Canvas canvas) {
//todo 绘制表盘
}
public static class BuilderImpl extends Builder {
private Context context;
private float textSize; //文字大小
public BuilderImpl(Context context) {
this.context = context;
}
@Override
public Builder setRadius(float radius) {
return this;
}
@Override
public Builder setTextSize(float textSize) {
this.textSize = textSize;
return this;
}
@Override
public Builder setBackgroundColor(int backgroundColor) {
return this;
}
@Override
public Builder setPadding(float padding) {
return this;
}
@Override
public ClockViewImpl create() {
ClockViewImpl clockView = new ClockViewImpl(context);
clockView.mTextSize = textSize;
return clockView;
}
}
}
//模仿构造模式
Builder builder1 = new ClockViewImpl.BuilderImpl(this);
builder1.setTextSize(12f);
ClockViewImpl clockViewImpl = builder1.create();
总结
我们自己通过自定义view 模拟了下系统的AlertDialog 的实现过程,区别是系统的AlertDialog 的创建是通过传入绑定的context,调用activity 中的windowmanager 上面产生的view,但builder 模式运用雷同。 优点:1、结构清晰,2、代码明了,3、方便维护
- 结构清晰,Builder设计模式结构基本固定,一个目标对象,一个Builder对象
- 代码明了,链式调用Builder提供的方法,自由组合多种组件,构建出多种不一样的目标产品
- 方便维护,面向抽象或接口的设计原则,上面的比如想扩展个属性,直接在build 类中添加,外部调用无需修改