建造者模式(Builder Pattern)使用多个简单的对象一步一步构建成一个复杂的对象。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
建造者模式的优点: 1.使用起来简单,让人感觉很好。 2.屏蔽了组件的内部细节,将组件本身和创建过程进行解耦分离,同一个 Builder 设置不同的参数,即可创建适应不同需求的组件。3.扩展容易,通过设置Builder的参数即可完成不同需求的定制。
缺点: 不适用于需求或者差异化比较大的组件。
下面看一段Android的代码
new AlertDialog.Builder(this)
.setTitle("title")
.setMessage("message")
.setIcon(R.mipmap.ic_launcher)
.create()
.show();
上面是Android弹出对话框的代码,代码看起来十分清晰,通过查看源码发现它是用了建造者模式。那么下面就看一下它怎么把我们定制的需求显示出来的吧。()
查看AlertDialog的源码,发现它的内部有一个AlertController的变量
public class AlertDialog extends AppCompatDialog implements DialogInterface {
private AlertController mAlert;
.......
}
进入AlertController,可以看到它的属性就是我们在代码里面设置的那些,所以在这里可以确定对话框显示的界面都是AlertController属性。
class AlertController {
private final Context mContext;
private final AppCompatDialog mDialog;
private final Window mWindow;
private CharSequence mTitle;
private CharSequence mMessage;
private ListView mListView;
private View mView;
private int mViewLayoutResId;
private int mViewSpacingLeft;
private int mViewSpacingTop;
private int mViewSpacingRight;
private int mViewSpacingBottom;
private boolean mViewSpacingSpecified = false;
private Button mButtonPositive;
private CharSequence mButtonPositiveText;
private Message mButtonPositiveMessage;
private Button mButtonNegative;
private CharSequence mButtonNegativeText;
private Message mButtonNegativeMessage;
private Button mButtonNeutral;
private CharSequence mButtonNeutralText;
private Message mButtonNeutralMessage;
private NestedScrollView mScrollView;
private int mIconId = 0;
private Drawable mIcon;
private ImageView mIconView;
private TextView mTitleView;
private TextView mMessageView;
private View mCustomTitleView;
private ListAdapter mAdapter;
private int mCheckedItem = -1;
private int mAlertDialogLayout;
private int mButtonPanelSideLayout;
private int mListLayout;
private int mMultiChoiceItemLayout;
private int mSingleChoiceItemLayout;
private int mListItemLayout;
private int mButtonPanelLayoutHint = AlertDialog.LAYOUT_HINT_NONE;
private Handler mHandler;
.........
}
Dialog是由它的静态内部类创建出来的,进入Builder发现它的内部也有一个AlertController.AlertParams的变量
public static class Builder {
private final AlertController.AlertParams P;
.......
}
进入AlertController.AlertParams发现它实际就是AlertController的Builder,用于保存AlertController的属性值。
public static class AlertParams {
public final Context mContext;
public final LayoutInflater mInflater;
public int mIconId = 0;
public Drawable mIcon;
public int mIconAttrId = 0;
public CharSequence mTitle;
public View mCustomTitleView;
public CharSequence mMessage;
public CharSequence mPositiveButtonText;
public DialogInterface.OnClickListener mPositiveButtonListener;
public CharSequence mNegativeButtonText;
public DialogInterface.OnClickListener mNegativeButtonListener;
public CharSequence mNeutralButtonText;
public DialogInterface.OnClickListener mNeutralButtonListener;
public boolean mCancelable;
public DialogInterface.OnCancelListener mOnCancelListener;
public DialogInterface.OnDismissListener mOnDismissListener;
public DialogInterface.OnKeyListener mOnKeyListener;
public CharSequence[] mItems;
........
}
到这里可以看出,我们的设置都是赋给AlertController的属性,所以到最后显示出来的也是AlertController里面的属性值。那么它是怎么显示到桌面的呢?
直接就看show()方法了
public void show() {
if (mShowing) {
if (mDecor != null) {
if (mWindow.hasFeature(Window.FEATURE_ACTION_BAR)) {
mWindow.invalidatePanelMenu(Window.FEATURE_ACTION_BAR);
}
mDecor.setVisibility(View.VISIBLE);
}
return;
}
mCanceled = false;
//如果没有创建就新建一个dialog视图
if (!mCreated) {
dispatchOnCreate(null);
}
onStart();
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 {
mWindowManager.addView(mDecor, l);
mShowing = true;
sendShowMessage();
} finally {
}
}
我们跟着 dispatchOnCreate(null)这方法一直找到Dialog类的Oncreate方法,可以看出它是交给子类来实现的。
protected void onCreate(Bundle savedInstanceState) {
}
既然是交给子类实现,那就找到AlertDialog的Oncreate方法
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mAlert.installContent();
}
可以发现,最终还是到mAlert.installContent()这里来,进入这个方法
public void installContent() {
final int contentView = selectContentView();
mDialog.setContentView(contentView);
setupView();
}
可以看出Dialog最后显示的界面就是contentView ,进入selectContentView()这个方法
private int selectContentView() {
if (mButtonPanelSideLayout == 0) {
return mAlertDialogLayout;
}
if (mButtonPanelLayoutHint == AlertDialog.LAYOUT_HINT_SIDE) {
return mButtonPanelSideLayout;
}
return mAlertDialogLayout;
}
所以正常情况下就返回mAlertDialogLayout这个布局,它是android定义好的一个布局
mAlertDialogLayout = a.getResourceId(R.styleable.AlertDialog_android_layout, 0);
那么我们设置的那些参数都去哪了?它都在 setupView()这个方法里面设置进去了,这里就不一一探究,读者可自行查看源码。
下面就用建造者模式模仿一个AlertDialog吧
先创建一个AlertController,它有一个内部类AlertParams,代码如下
public class AlertController {
private String title;
private String content;
private String footer;
public AlertController() {
}
public void setTitle(String title) {
this.title = title;
}
public void setContent(String content) {
this.content = content;
}
public void setFooter(String footer) {
this.footer = footer;
}
public void Show() {
System.out.println(this);
}
@Override
public String toString() {
return "AlertController [title=" + title + ", content=" + content + ", footer=" + footer + "]";
}
public static class AlertParams{
public String title;
public String content;
public String footer;
public AlertParams() {
}
public void applyto(AlertController dialog) {
if (title != null) {
dialog.setTitle(title);
}
if (content != null) {
dialog.setContent(content);
}
if (footer != null) {
dialog.setFooter(footer);
}
}
}
}
然后再创建一个AlertDialog类,它有一个内部类Builder,代码如下
public class AlertDialog {
private AlertController alertController;
public AlertDialog() {
alertController = new AlertController();
}
public void show() {
alertController.Show();
}
public static class Builder{
AlertController.AlertParams params;
public Builder() {
params = new AlertController.AlertParams();
}
public Builder setTitle(String title) {
params.title = title;
return this;
}
public Builder setContent(String content) {
params.content = content;
return this;
}
public Builder setFooter(String footer) {
params.footer = footer;
return this;
}
public AlertDialog create() {
AlertDialog dialog = new AlertDialog();
params.applyto(dialog.alertController);
return dialog;
}
}
}
然后测试一下:
public class Main {
public static void main(String[] args) {
new AlertDialog.Builder()
.setTitle("this is title")
.setContent("this is content")
.create()
.show();
}
}
结果如下:
以上只是一种没有指挥者的建造者模式,现在对设计模式只是很浅层面的了解,只是让自己看一些框架源码的时候能够对它的架构更加清晰。至于更深层次的了解,要到做项目时发现自己代码的问题,从而联想起某种设计模式并对代码进行优化改造,我想那时候对某个设计模式的了解就更加深刻了。