模式的介绍
模式的定义
建造者模式(Builder Pattern)也叫生成器模式,定义如下:
Seperate the construction of a complex object from its represention so that the same construction process can create different representions.
将一个复杂对象的构建与他的表示分开,使得同样的构建过程可以创建不同的表示。
模式的使用场景
- 相同的方法,不同的执行顺序,产生不同的事件结果
- 多个部件或零件,都可以装配到一个对象中,但是产生的运行结果又不相同
- 产品类非常复杂,或者产品类中调用顺序不同产生不同的效果
UML类图
角色介绍
- Product 产品类 :
产品的抽象类,通常是实现了模板方法的模式 - Builder 抽象建造者 :
抽象类, 规范产品的组建,一般是由子类实现具体的组件过程。
- ConcreteBuilder 具体建造者:
具体的构建器,返回一个组建好的对象
- Director :
统一组装过程(可省略)。
模式的简单实现
样例的简单介绍
在android中,AlertDialog的生成Builder是一个经典的建造者模式,我们可以采用建造者模式模拟AlertDialog的生成。
模拟实现:
AbstractAlertDialog类:抽象类,描述了对话框的title,message,icon, positiveButton ,neutralButton ,negativeButton ,show()方法模拟对话框弹出。
public abstract class AbstractAlertDialog {
protected String title = "Title";
protected String message = "Message";
protected String icon = "Icon";
protected String positiveButton = "PositiveButton";
protected String neutralButton = "NeutralButton";
protected String negativeButton = "NegativeButton";
public abstract void setTitle(String title);
public abstract void setMessage(String message);
public abstract void setIcon(String icon);
public abstract void setPositiveButton(String positiveButton);
public abstract void setNeutralButton(String neutralButton);
public abstract void setNegativeButton(String negativeButton);
public void show(){
System.out.println("AlertDialog: "+" title == " + title +",message == "+message
+" ,icon==" + icon+ ",\n + PositiveButton == " + positiveButton
+",neutralButton =="+neutralButton +",negativeButton == "+negativeButton);
}
}
AlertDialog类:模拟对话框的具体类
public class AlertDialog extends AbstractAlertDialog{
@Override
public void setTitle(String title) {
// TODO Auto-generated method stub
super.title = title;
}
@Override
public void setMessage(String message) {
// TODO Auto-generated method stub
super.message = message;
}
@Override
public void setIcon(String icon) {
// TODO Auto-generated method stub
super.icon = icon;
}
@Override
public void setPositiveButton(String positiveButton) {
// TODO Auto-generated method stub
super.positiveButton = positiveButton;
}
@Override
public void setNeutralButton(String neutralButton) {
// TODO Auto-generated method stub
super.neutralButton = neutralButton;
}
@Override
public void setNegativeButton(String negativeButton) {
// TODO Auto-generated method stub
super.negativeButton = negativeButton;
}
}
AbstractBuilder :抽象建造类
public abstract class AbstractBuilder {
public abstract void setTitle(String title);
public abstract void setMessage(String message);
public abstract void setIcon(String icon);
public abstract void setPositiveButton(String positiveButton);
public abstract void setNeutralButton(String neutralButton);
public abstract void setNegativeButton(String negativeButton);
public abstract AbstractAlertDialog create();
}
Builder :具体的建造类
public class Builder extends AbstractBuilder {
private AbstractAlertDialog alertDialog = new AlertDialog();
@Override
public void setTitle(String title) {
// TODO Auto-generated method stub
alertDialog.setTitle(title);
}
@Override
public void setMessage(String message) {
// TODO Auto-generated method stub
alertDialog.setMessage(message);
}
@Override
public void setIcon(String icon) {
// TODO Auto-generated method stub
alertDialog.setIcon(icon);
}
@Override
public void setPositiveButton(String positiveButton) {
// TODO Auto-generated method stub
alertDialog.setPositiveButton(positiveButton);
}
@Override
public void setNeutralButton(String neutralButton) {
// TODO Auto-generated method stub
alertDialog.setNeutralButton(neutralButton);
}
@Override
public void setNegativeButton(String negativeButton) {
// TODO Auto-generated method stub
alertDialog.setNegativeButton(negativeButton);
}
@Override
public AbstractAlertDialog create() {
// TODO Auto-generated method stub
return alertDialog;
}
}
Direct :导演类
public class Direct {
private AbstractBuilder mbuilder = null;
public Direct(AbstractBuilder builder){
mbuilder = builder;
}
public AbstractBuilder constructor(String title,String message,String icon,
String positiveButton,String neutralButton,String negativeButton){
mbuilder.setTitle(title);
mbuilder.setMessage(message);
mbuilder.setIcon(icon);
mbuilder.setPositiveButton(positiveButton);
mbuilder.setNeutralButton(neutralButton);
mbuilder.setNegativeButton(negativeButton);
return mbuilder;
}
}
MainFunction 类:
public class MainFunction {
public static void main(String[] args) {
// TODO Auto-generated method stub
AbstractBuilder builder = new Builder();
Direct direct = new Direct(builder);
direct.constructor("myTitle", "myMessage", "myIcon",
"myPositiveButton", "myNeutralButton", "myNegativeButton").create().show();
}
}
程序输出:
AlertDialog: title == myTitle,message == myMessage ,icon==myIcon,
+ PositiveButton == myPositiveButton,neutralButton ==myNeutralButton,negativeButton == myNegativeButton
从输出我们可以看到,我们生成了一个AlertDialog,其title,message,icon,PositiveButton,neutralButton,negativeButton为我们定义的值。
我们是不是觉得,这个AlertDialog和我们平时使用的方式不对啊,并且感觉这个方法还更复杂,并且不灵活。
对的,这是因为我完全对比建造者模式来模拟的,而android中对AlertDialog生成是简化了的建造者模式。我们修改一下代码,
public class MainFunction {
public static void main(String[] args) {
// TODO Auto-generated method stub
AbstractBuilder builder = new Builder();
builder.setIcon(" testIcon");
builder.setMessage(" testMessage");
builder.setNegativeButton("test_negativeButton");
builder.setNeutralButton("test_neutralButton");
builder.setPositiveButton("test_positiveButton");
builder.setTitle("test_title");
builder.create().show();
}
}
看到没,现在的使用方法是不是和android中AlertDialog的使用方法一样了。对的,这也就是说android中的AlertDialog的建造生成者模式是没有使用Direct类,直接在Builder中组装生成。
程序输出:
AlertDialog: title == test_title,message == testMessage ,icon== testIcon,
+ PositiveButton == test_positiveButton,neutralButton ==test_neutralButton,negativeButton == test_negativeButton
模式的优缺点
优点
- 封装性
使用建造者模式可以不需要知道产品内部的组成细节
- 建造者独立,容易扩展
- 便于控制细节风险
由于具体的建造模式是独立的,因此可以对建造过程逐步细化,而不对其他的模块产生任何的影响
缺点
- 会产生多余的Builder对象以及Director对象,消耗内存
- 对象的构建过程暴露
Android源码中的模式实现
在Android源码中,我们最常用到的Builder模式就是AlertDialog.Builder, 使用该Builder来构建复杂的AlertDialog对象。
private void showDialog(Context context) {
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setIcon(R.drawable.ic_launcher);
builder.setTitle("Title");
builder.setMessage("Message");
builder.setPositiveButton("Button1",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
setTitle("点击了对话框上的Button1");
}
});
builder.setNeutralButton("Button2",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
setTitle("点击了对话框上的Button2");
}
});
builder.setNegativeButton("Button3",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
setTitle("点击了对话框上的Button3");
}
});
builder.create().show();
}
生成AlertDialog如图:
现在,我们对应的查看AlertDialog的源码:
./frameworks/base/core/java/android/app/AlertDialog.java
关键代码:
public class AlertDialog extends Dialog implements DialogInterface {
private AlertController mAlert;
.........
//构造函数
protected AlertDialog(Context context) {
this(context, resolveDialogTheme(context, 0), true);
}
protected AlertDialog(Context context, int theme) {
this(context, theme, true);
}
AlertDialog(Context context, int theme, boolean createThemeContextWrapper) {
super(context, resolveDialogTheme(context, theme), createThemeContextWrapper);
mWindow.alwaysReadCloseOnTouchAttr();
mAlert = new AlertController(getContext(), this, getWindow());
}
protected AlertDialog(Context context, boolean cancelable, OnCancelListener cancelListener) {
super(context, resolveDialogTheme(context, 0));
mWindow.alwaysReadCloseOnTouchAttr();
setCancelable(cancelable);
setOnCancelListener(cancelListener);
mAlert = new AlertController(context, this, getWindow());
}
//setter方法
@Override
public void setTitle(CharSequence title) {
super.setTitle(title);
mAlert.setTitle(title);
}
public void setCustomTitle(View customTitleView) {
mAlert.setCustomTitle(customTitleView);
}
public void setMessage(CharSequence message) {
mAlert.setMessage(message);
}
public void setView(View view) {
mAlert.setView(view);
}
....................
//Builer
public static class Builder {
private final AlertController.AlertParams P;
private int mTheme;
//Builder构造函数
public Builder(Context context) {
this(context, resolveDialogTheme(context, 0));
}
public Builder(Context context, int theme) {
P = new AlertController.AlertParams(new ContextThemeWrapper(
context, resolveDialogTheme(context, theme)));
mTheme = theme;
}
public Context getContext() {
return P.mContext;
}
//Builder中的setter方法
public Builder setTitle(int titleId) {
P.mTitle = P.mContext.getText(titleId);
return this;
}
public Builder setTitle(CharSequence title) {
P.mTitle = title;
return this;
}
public Builder setCustomTitle(View customTitleView) {
P.mCustomTitleView = customTitleView;
return this;
}
public Builder setMessage(int messageId) {
P.mMessage = P.mContext.getText(messageId);
return this;
}
public Builder setMessage(CharSequence message) {
P.mMessage = message;
return this;
}
public Builder setIcon(int iconId) {
P.mIconId = iconId;
return this;
}
public Builder setIcon(Drawable icon) {
P.mIcon = icon;
return this;
}
....................
//create方法,返回一个AlertDialog对象
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;
}
//show方法
public AlertDialog show() {
AlertDialog dialog = create();
dialog.show();
return dialog;
}
}
}
从源码来看,android中的AlertDialog的建造生成者模式是没有使用Direct类,直接在Builder中组装生成。Builder同时扮演了上文中提到的builder、ConcreteBuilder、Director的角色,简化了Builder模式的设计。
参考资料
(1).设计模式之禅—第11章 建造者模式
(2)Android设计模式源码解析之Builder模式
https://github.com/simple-android-framework/android_design_patterns_analysis/tree/master/builder/mr.simple