设计模式之二:Builder模式
目录介绍php
0.本人写的综合案例git
1.1 定义: 将一个复杂对象的构建与它的表示分离,使得一样的构建过程能够建立不一样的展现。
1.2 Builder模式属于建立型,一步一步将一个复杂对象建立出来,容许用户在不知道内部构建细节的状况下,能够更精细地控制对象的构造流程。github
相同方法,不一样执行顺序,产生不一样事件结果
初始化对象特别复杂,参数众多,且不少参数都具备默认值时设计模式
3.1 Builder模式UML图(摘自网络)安全
3.2 在《Android源码设计模式》这本书上,介绍经典Builder模式中,包括网络
3.3 Product角色app
//设置抽象类 public abstract class BuilderUser { protected String name; protected String cardID; protected int age; protected String address; public BuilderUser() {} //设置名字 public void setName(String name) { this.name = name; } //抽象方法 public abstract void setCardID(); //设置年龄 public void setAge(int age) { this.age = age; } //设置地址 public void setAddress(String address) { this.address = address; } @Override public String toString() { return "BuilderUser{" + "name='" + name + ''' + ", cardID='" + cardID + ''' + ", age=" + age + ", address='" + address + ''' + '}'; } } /** * 具体的Product角色 UserCard */ public class UserCard extends BuilderUser { public UserCard() {} @Override public void setCardID() { cardID="10086"; //设置默认ID } }
3.4 Builder : 抽象Builder类,规范产品组建,通常是由子类实现具体的组建过程ide
/** * 抽象Builder类 */ public abstract class Builder { public abstract void buildName(String name); public abstract void buildCardID(); public abstract void buildAge(int age); public abstract void buildAddress(String address); public abstract BuilderUser create(); }
3.5 ConcreteBuilder : 具体的Builder类函数
/** * 具体的Builder类 */ public class AccountBuilder extends Builder{ private BuilderUser user = new UserCard(); @Override public void buildName(String name) { user.setName(name); } @Override public void buildCardID() { user.setCardID(); } @Override public void buildAge(int age) { user.setAge(age); } @Override public void buildAddress(String address) { user.setAddress(address); } @Override public BuilderUser create() { return user; } }
3.6 Director : 统一组装过程布局
/** * Director角色,负责构造User */ public class Director { Builder mBuilder =null; public Director(Builder builder){ this.mBuilder =builder; } public void construct(String name,int age,String address){ mBuilder.buildName(name); mBuilder.buildCardID(); mBuilder.buildAge(age); mBuilder.buildAddress(address); } }
4.1 实际开发中,有时会遇到复杂的对象的代码,好比
public class BuilderDemo { private final String name; //必选 private final String cardID; //必选 private final int age; //可选 private final String address; //可选 private final String phone; //可选 }
4.2 经过构造函数的参数形式去写一个实现类,或者经过set,get去实现
BuilderDemo(String name); BuilderDemo(String name, String cardID); BuilderDemo(String name, String cardID,int age); BuilderDemo(String name, String cardID,int age, String address); BuilderDemo(String name, String cardID,int age, String address,String phone);
4.3 分析
4.4 将上面例子改为builder模式以下所示
public class BuilderDemo { private final String name; //必选 private final String cardID; //必选 private final int age; //可选 private final String address; //可选 private final String phone; //可选 public BuilderDemo(UserBuilder userBuilder){ this.name=userBuilder.name; this.cardID=userBuilder.cardID; this.age=userBuilder.age; this.address=userBuilder.address; this.phone=userBuilder.phone; } public static class UserBuilder{ private final String name; private final String cardID; private int age; private String address; private String phone; public BuilderDemo build(){ return new BuilderDemo(this); } public UserBuilder(String name,String cardID){ this.name=name; this.cardID=cardID; } public UserBuilder age(int age){ this.age=age; return this; } public UserBuilder address(String address){ this.address=address; return this; } public UserBuilder phone(String phone){ this.phone=phone; return this; } } }
4.5 最后运用,代码以下
new BuilderDemo.UserBuilder("yc","10086") .age(24) .address("beijing") .phone("13667225184") .build();
4.6 关于线程安全问题
// 线程安全 public BuilderDemo build(){ BuilderDemo builderDemo = new BuilderDemo(this); if(builderDemo.age > 100){ throw new IllegalStateException("Age out of range"); } return builderDemo; } // 线程不安全,不要这样写 public BuilderDemo build(){ if(age > 100){ throw new IllegalStateException("Age out of range"); } return new BuilderDemo(this); }
5.1 首先看看AlertDialog.Builder源代码,只是摘自部分代码
public class AlertDialog extends AppCompatDialog implements DialogInterface { //接收builder成员变量p中各个参数 final AlertController mAlert; //下面是三个构造函数 protected AlertDialog(@NonNull Context context) { this(context, 0); } protected AlertDialog(@NonNull Context context, @StyleRes int themeResId) { super(context, resolveDialogTheme(context, themeResId)); mAlert = new AlertController(getContext(), this, getWindow()); } protected AlertDialog(@NonNull Context context, boolean cancelable, @Nullable OnCancelListener cancelListener) { this(context, 0); setCancelable(cancelable); setOnCancelListener(cancelListener); } //事件上这里调用了是mAlert的setView方法 public void setView(View view) { mAlert.setView(view); } public void setView(View view, int viewSpacingLeft, int viewSpacingTop, int viewSpacingRight, int viewSpacingBottom) { mAlert.setView(view, viewSpacingLeft, viewSpacingTop, viewSpacingRight, viewSpacingBottom); } public static class Builder { //这个里面存放不少参数 private final AlertController.AlertParams P; //这个是new AlertDialog.Builder(context,R.style.AppTheme)调用的方法 public Builder(@NonNull Context context, @StyleRes int themeResId) { P = new AlertController.AlertParams(new ContextThemeWrapper( context, resolveDialogTheme(context, themeResId))); mTheme = themeResId; } //这部分代码省略不少,主要是set设置各类参数 public Builder setTitle(@Nullable CharSequence title) { P.mTitle = title; return this; } //这部分代码省略不少,主要是set设置各类参数 public Builder setView(int layoutResId) { P.mView = null; P.mViewLayoutResId = layoutResId; P.mViewSpacingSpecified = false; return this; } //构建dialog,传递参数 public AlertDialog create() { final AlertDialog dialog = new AlertDialog(P.mContext, mTheme); 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; } //展现dialog public AlertDialog show() { final AlertDialog dialog = create(); dialog.show(); return dialog; } } }
5.2 接下来看看build源代码
public AlertDialog create() { //建立 final AlertDialog dialog = new AlertDialog(P.mContext, mTheme); //这一步很重要,下面会单独分析 P.apply(dialog.mAlert); //设置是否能够取消,默认是true dialog.setCancelable(P.mCancelable); if (P.mCancelable) { dialog.setCanceledOnTouchOutside(true); } //设置取消监听 dialog.setOnCancelListener(P.mOnCancelListener); //设置dialog关闭后监听 dialog.setOnDismissListener(P.mOnDismissListener); //设置返回键监听 if (P.mOnKeyListener != null) { dialog.setOnKeyListener(P.mOnKeyListener); } //返回对象,建立成功 return dialog; }
5.3 接下来看看show的代码
public void show() { //若是弹窗已经show出来了 if (mShowing) { //若是顶级view存在则设置窗口window,并显示顶级View 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) { dispatchOnCreate(null); } //得到Windowd的顶级View,并将其添加到对应的WindowManager中,而后发送show的消息 onStart(); //获取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); } //获取布局参数 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 { //将mDecor添加到WindowManager中 mWindowManager.addView(mDecor, l); mShowing = true; //发送一个显示Dialog消息 sendShowMessage(); } finally { } }
(2)而后接着调用onStart函数
(3)最后将Dialog的mDecor添加到WindowManager中(有点不明白这里,为何要获取到最顶部的布局)
5.4 为何AlertDialog要使用builder模式呢?
AlertDialog(String title); AlertDialog(String message) AlertDialog(int resId) AlertDialog(int resId, String title, String message); AlterDialog(int resId, String title, String message, String PositiveButtonString, OnClickListener listener); AlterDialog(int resId, String title, String message, String PositiveButtonString, OnClickListener listener); AlterDialog(int resId, String title, String message, String NegativeButtonString, OnClickListener listener); AlterDialog(int resId, String title, String message, String PositiveButtonString, OnClickListener listener, String NegativeButtonString, OnClickListener listener); ....
6.1 Builder模式有几个好处:
6.2 固然Builder模式也有缺点:
7.1 参考案例