设计模式七 Builder模式
来源:互联网 发布:觉醒字幕组知乎 编辑:程序博客网 时间:2024/05/18 20:11
农历2015年的最后一篇blog。
该篇为《Android 源码设计模式 解析与实践》Builder设计模式的读书笔记
Builder模式是什么?
Builder模式如同其名,其是一步一步创建一个复杂对象的创建型模式。该模式可以将一个复杂的对象与它的表示分离:做到同样的构建过程可以有不同的表示。
我们在什么场景下使用该模式:
当初始化一个对象特别复杂,参数多,且很多参数都具有默认值的时候,可以使用Builder模式。
Builder模式在日常Android开发当中,也是被我们经常用到,几乎每个Android程序员都用到过,只是自己不知道当前的代码已经蕴含了Builder模式在里面:
下面记录一段现在手中项目当中的一段代码:
PhotoGraph.Builder builder = new PhotoGraph.Builder(request.getContext());builder.setEventTime(event.getTmGen()) .setLiftNumber(liftNo) .setPriority(PhotoGraphConfig.LIFT_FAULT_PRIORITY) .setZipFileName(zipFileName) .setOnPhotoListener(new OnPhotoListener() { @Override public void openCameraFailure() { //... } @Override public void onCompletion(String filePath) { //... } });TaskPhotoGraph.getInstance().put(builder.create());
该代码片段就使用了Builder模式,下面在给出我们经常使用的AlertDialog代码:
AlertDialog.Builder builder = new AlertDialog.Builder(this);builder.setTitle("提示") .setMessage("Message...") .setPositiveButton("确定", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { // .... } }).setNegativeButton("取消", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { // ... } });builder.show();
ok,上面的代码片段就是我们经常要使用AlertDialog的实现,其实从类名就能看出是一个Builder模式,通过builder对象去组装AlertDialog的各个参数(如上面的Title、Message、PositiveButton、NegativeButton等),将AlertDialog的表示与构造进行了分离。
那既然知道了Builder模式是怎么个样子,下面就来分析分析Builder模式的实现,这里以AlertDialog的源码作为示例:
public class AlertDialog extends Dialog implements DialogInterface { private AlertController mAlert; // mAlert 接受Builder成员变量p中各个参数 // ...省略一些代码 @Override public void setTitle(CharSequence title) { super.setTitle(title); mAlert.setTitle(title); } public void setMessage(CharSequence message) { mAlert.setMessage(message); } public static class Builder { // 存储 AlertDialog的各个参数,用于创建AlertDialog的时候传递给AlertDialog的成员变量mAlert private final AlertController.AlertParams P; // ...省略一些代码 public Builder(Context context) { this(context, resolveDialogTheme(context, 0)); } // 设置各种参数 public Builder setTitle(int titleId) { P.mTitle = P.mContext.getText(titleId); return this; } public Builder setMessage(int messageId) { P.mMessage = P.mContext.getText(messageId); return this; } public Builder setPositiveButton(CharSequence text, final OnClickListener listener) { P.mPositiveButtonText = text; P.mPositiveButtonListener = listener; return this; } public Builder setNegativeButton(CharSequence text, final OnClickListener listener) { P.mNegativeButtonText = text; P.mNegativeButtonListener = listener; return this; } } public AlertDialog create() { final AlertDialog dialog = new AlertDialog(P.mContext, mTheme, false); // 将Builder中p的参数传递应用到AlertDialog中的mAlert对象中 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; } }
以上代码是从android.app.AlertDialog.java 类中截取的代码片。
从上述代码中,我们能知道的是:
- Builder类可以设置AlertDialog中需要用到的一切参数
- Builder 成员变量AlertController.AlertParams p用来存储AlertDialog待用的参数
- AlertDialog中的成员变量 mAlert对象中包含了与p一 一对应的成员变量
- Builder的create()方法中,会调用 p.apply(dialog.mAlert) 方法将p中早先设置的参数一 一传递到AlertDialog 的 mAlert 对象中
到这里为止,我们为Builder设置的一系列参数,已经全部由Builder 的成员变量AlertController.AlertParams p转移到了AlertDialog成员变量 mAlert对象中。这里我们不禁有一点疑惑了:
为什么传递这一系列参数要这么麻烦,要用到AlertController.AlertParam 和 AlertController 这两个对象去交接?为什么不在Builder类中一系列setXXX方法中将参数直接赋值给mAlert对应的成员变量
解释这一点很简单。这里可以仔细看看Builder类的声明为静态内部类,众所周知:java语法中静态类方法中无法引用非静态成员变量,也无法调用非静态方法。
而上面为什么可以使用AlertController.AlertParams p变量去存储设置给Builder的参数呢,答案很简单,因为在AlertController类中AlertParams类也是一个静态内部类。
以上就是Builder模式的一个具体实现。
现在接着往下看:AlertDialog现在只是拿到了这些参数(因为AlertDialog拥有AlertController 类型成员变量 mAlert ),后面在哪里使用到了这些参数呢?我们看看AlertDialog的show()方法
public AlertDialog show() { AlertDialog dialog = create(); dialog.show(); return dialog; }
AlertDialog的show()方法实际上又是调用了Dialog的show()方法(AlertDialog 继承 Dialog)
public void show() { if (mShowing) { // 如果已经显示,直接return if (mDecor != null) { if (mWindow.hasFeature(Window.FEATURE_ACTION_BAR)) { mWindow.invalidatePanelMenu(Window.FEATURE_ACTION_BAR); } mDecor.setVisibility(View.VISIBLE); } return; } mCanceled = false; if (!mCreated) { // 1、调用onCreate() dispatchOnCreate(null); } // 2、调用onStart() onStart(); // 3、获取DecorView mDecor = mWindow.getDecorView(); if (mActionBar == null && mWindow.hasFeature(Window.FEATURE_ACTION_BAR)) { final ApplicationInfo info = mContext.getApplicationInfo(); mWindow.setDefaultIcon(info.icon); mWindow.setDefaultLogo(info.logo); mActionBar = new WindowDecorActionBar(this); } // 4、获取布局参数 WindowManager.LayoutParams l = mWindow.getAttributes(); if ((l.softInputMode & WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) == 0) { WindowManager.LayoutParams nl = new WindowManager.LayoutParams(); nl.copyFrom(l); nl.softInputMode |= WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION; l = nl; } try { // 5、将mDecor添加到WindowManager中 mWindowManager.addView(mDecor, l); mShowing = true; // 6、发送显示Dialog的消息 sendShowMessage(); } finally { } }
上面代码已经添加了注释,主要也就是做了注释中的6件事,从这6件事当中,我们能看到一些关于Dialog生命周期的方法,根据以往经验(回想下Activity的onCreate()方法中的setContentView(R.layout.activity_xxx_xxx);),一般在onCreate()方法中去构建AlertDialog视图内容。
上面注释1中调用了dispatchOnCreate()方法
void dispatchOnCreate(Bundle savedInstanceState) { if (!mCreated) { onCreate(savedInstanceState); mCreated = true; }}
dispatchOnCreate()方法中又调用了onCreate()方法,onCreate()方法在Dialog中是一个空实现
protected void onCreate(Bundle savedInstanceState) {}
上面已经说过AlertDialog继承Dialog那么具体实现应该在AlertDialog中
@Overrideprotected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mAlert.installContent();}
onCreate()方法中我们一眼看到,这里终于又回到了使用了mAlert对象(忘记了mAlert对象的,请回过头看下)
public void installContent() { // 设置窗口没有title栏 mWindow.requestFeature(Window.FRATURE_NO_TITLE); // 设置窗口视图布局 mWindow.setContentView(mAlertDialogLayout); //mAlertDialogLayout是默认的窗口视图布局对象 // 设置窗口的其它子视图内容 setupView();}
这里调用mAlert的installContent()方法,在该方法中主要做了两件事:
调用Window对象的setContentView()方法(这里setContentView()同Activity的setContentView(),实际上Activity的setContentView()最终也是调用的Window对象setContentView())。因此这里就是设置AlertDialog布局的视图内容。
调用setupView(),为AlertDialog设置各项参数(即title、message 、icon、button等这些内容)
到此,我们在最开始使用Builder模式构建的一系列参数在setupView()方法中都得到了应用。
现在再回到之前AlertDialog的show()方法那里
if (!mCreated) { // 1、调用onCreate() dispatchOnCreate(null);}// ...省略一些代码// 3、获取DecorViewmDecor = mWindow.getDecorView();// ...省略一些代码// 5、将mDecor添加到WindowManager中mWindowManager.addView(mDecor, l);mShowing = true;// 6、发送显示Dialog的消息sendShowMessage();
setupView()结束后,我们的视图内容填充完毕,视图布局也全部设置完成,并且关联到了Window对象,即mWindow拥有这个视图内容以及布局。到这里注释1的方法执行完毕,接着通过注释3、5、6的代码,显而易见:
WindowManager会将Window对象的DecorView(即之前关联到Window对象的视图内容和视图布局)添加到用户窗口上,并显示出来。用户也就看到了弹出来的AlertDialog。
以上就是对Builder设计模式的读书笔记。主要涉及到了:
- Builder设计模式的实现
- AlertDialog源码解析
同时如果弄清楚了AlertDialog源码,那么现在自定义自己的Dialog也是非常轻松的。
以上如有纰漏,不吝指出!
- 设计模式七 Builder模式
- 设计模式:Builder模式
- 设计模式 -- BUILDER模式
- 【设计模式】Builder模式
- 设计模式-Builder模式
- 设计模式Builder模式
- 设计模式-Builder模式
- 设计模式 - Builder模式
- 设计模式 - Builder模式
- 设计模式---Builder模式
- 设计模式--Builder模式
- 设计模式---Builder模式
- 设计模式--Builder模式
- 设计模式---Builder模式
- 设计模式---Builder模式
- 设计模式-builder模式
- 【设计模式】Builder模式
- 设计模式----Builder模式
- Seismo come from Finland and China
- HttpClient 教程 (三)
- 使用Android Studio将Android项目打aar包
- 从getView()重复调用浅谈listview数据装载机制
- Kafka文件存储机制那些事
- 设计模式七 Builder模式
- 利用fiddler模拟发送json数据的post请求
- struts2通过ajax动态改变系统后台的语言来达到国际化页面切换的功能
- iOS开发——手机号,密码,邮箱,身份证号,中文判断
- spring4.2 定时任务
- Javascript中如何获取统一管理的Java提示语
- Android Jni开发之交互处理
- Lambda表达式详解
- CSS中,margin的折叠(collapsing )问题