跳到主要内容 Android 设计模式:Builder 模式详解与应用 | 极客日志
Java java
Android 设计模式:Builder 模式详解与应用 建造者模式(Builder Pattern)是一种创建型设计模式,旨在将复杂对象的构建与表示分离。详细阐述了 Builder 模式的定义、使用场景及 UML 结构,通过组装电脑的示例演示了抽象构建器、具体构建器和指挥者的协作流程。重点分析了 Android 源码中 AlertDialog.Builder 的实现原理,展示了如何通过链式调用设置参数并构建对象。此外,还探讨了在实际项目中自定义万能 Dialog 的应用方式,总结了该模式的优缺点及适用建议,帮助开发者理解如何在 Android 开发中优雅地处理复杂对象初始化。
w795471 发布于 2025/2/7 更新于 2026/4/21 0 浏览建造者模式(Builder Pattern)是一种创建型设计模式,其核心目的是将复杂对象的构建过程与表示分离。它允许客户端在不了解对象内部具体构造细节的情况下,通过逐步调用的方式精细控制对象的创建流程。在 Android 开发中,Builder 模式被广泛用于处理具有多个可选参数的对象初始化,有效解决了构造函数参数过多导致的'伸缩构造函数'问题。
模式的使用场景
相同的方法执行顺序不同,产生不同的结果时;
多个部件或零件可以装配到一个对象中,但产生的运行结果不同时;
产品类非常复杂,或者产品类中的调用顺序不同产生了不同的效能,此时使用建造者模式非常合适。
UML 类图结构 虽然无法直接展示图片,但 Builder 模式的经典 UML 结构包含以下角色:
Product(产品类) :定义被构建的复杂对象,通常包含多个属性。
Builder(抽象构建器) :规范产品的组建过程,一般由子类实现具体的组件过程,声明了构建各个部分的方法。
ConcreteBuilder(具体构建器) :实现抽象构建器接口,负责在具体步骤中组装产品对象。
Director(指挥者) :统一组装过程,决定构建的顺序和逻辑,可省略。
Builder 模式简单实现 Builder 模式最典型的例子是组装电脑。下面通过 Java 代码演示完整的实现流程。
1. 创建产品类 public class Computer {
private String mCpu;
private String mRam;
private String mMainboard;
public void setmCpu (String mCpu) {
this .mCpu = mCpu;
}
public void setmRam (String mRam) {
this .mRam = mRam;
}
public void setmMainboard (String mMainboard) {
this .mMainboard = mMainboard;
}
@Override
public String toString () {
return "Computer{" +
"mCpu='" + mCpu + '\'' +
", mRam='" + mRam + '\'' +
", mMainboard='" + mMainboard + '\'' +
'}' ;
}
}
2. 创建抽象 Builder 类 组装电脑有一套固定的模版,即抽象的 Builder 类。它提供了安装 CPU、内存、主板的方法,以及最终组装成电脑的 create 方法。
public abstract class Builder {
public abstract void buildCpu (String cpu) ;
public abstract void buildRam (String ram) ;
public abstract void buildMainboard (String mainboard) ;
public abstract Computer create () ;
}
3. 实现具体构建器 ComputerBuilder 类用于具体组装电脑,继承自抽象 Builder 类。
public class ComputerBuilder extends Builder {
private Computer mComputer = new Computer ();
@Override
public void buildCpu (String cpu) {
mComputer.setmCpu(cpu);
}
@Override
public void buildRam (String ram) {
mComputer.setmRam(ram);
}
@Override
public void buildMainboard (String mainboard) {
mComputer.setmMainboard(mainboard);
}
@Override
public Computer create () {
return mComputer;
}
}
4. 指挥者类统一组装过程 Director 类负责指挥具体的构建步骤,确保流程规范。
public class Director {
private Builder mBuilder;
public Director (Builder builder) {
this .mBuilder = builder;
}
public Computer createComputer (String cpu, String mainboard, String ram) {
mBuilder.buildMainboard(mainboard);
mBuilder.buildRam(ram);
mBuilder.buildCpu(cpu);
return mBuilder.create();
}
}
5. 客户端调用 最后商家(客户端)用指挥者类组装电脑。我们只需要提供想要的配置,至于商家怎样组装的电脑无需知道。
public class Client {
public static void main (String[] args) {
Builder mBuilder = new ComputerBuilder ();
Director mDirector = new Director (mBuilder);
Computer computer = mDirector.createComputer("i5-3210" , "DDR4" , "Gigabyte B450" );
System.out.println(computer.toString());
}
}
Android 源码中的 Builder 模式 在 Android 源码中,最常用到的 Builder 模式就是 AlertDialog.Builder。使用该 Builder 来构建复杂的 AlertDialog 对象,避免了构造函数参数过多的问题。
简单示例
private void showDialog (Context context) {
AlertDialog.Builder builder = new AlertDialog .Builder(context);
builder.setIcon(R.drawable.icon);
builder.setTitle("头部" );
builder.setMessage("内容" );
builder.setPositiveButton("Button1" ,
new DialogInterface .OnClickListener() {
public void onClick (DialogInterface dialog, int whichButton) {
setTitle("点击了对话框上的 Button1" );
}
})
.setNeutralButton("Button2" ,
new DialogInterface .OnClickListener() {
public void onClick (DialogInterface dialog, int whichButton) {
setTitle("点击了对话框上的 Button2" );
}
});
builder.create().show();
}
源码分析 查看 AlertDialog 的相关源码可以发现其内部机制:
public class AlertDialog extends Dialog implements DialogInterface {
private AlertController mAlert;
protected AlertDialog (Context context, int theme) {
this (context, theme, true );
}
AlertDialog(Context context, int theme, boolean createContextWrapper) {
super (context, resolveDialogTheme(context, theme), createContextWrapper);
mWindow.alwaysReadCloseOnTouchAttr();
mAlert = new AlertController (getContext(), this , getWindow());
}
@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 static class Builder {
private final AlertController.AlertParams P;
private int mTheme;
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 Builder setTitle (CharSequence title) {
P.mTitle = title;
return this ;
}
public Builder setMessage (CharSequence message) {
P.mMessage = message;
return this ;
}
public Builder setIcon (int iconId) {
P.mIconId = iconId;
return this ;
}
public Builder setPositiveButton (CharSequence text, final OnClickListener listener) {
P.mPositiveButtonText = text;
P.mPositiveButtonListener = listener;
return this ;
}
public Builder setView (View view) {
P.mView = view;
P.mViewSpacingSpecified = false ;
return this ;
}
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);
if (P.mOnKeyListener != null ) {
dialog.setOnKeyListener(P.mOnKeyListener);
}
return dialog;
}
}
}
可以看到,通过 Builder 来设置 AlertDialog 中的 title, message, button 等参数,这些参数都存储在类型为 AlertController.AlertParams 的成员变量 P 中。在调用 Builder 类的 create 函数时才创建 AlertDialog,并且将 Builder 成员变量 P 中保存的参数应用到 AlertDialog 的 mAlert 对象中,即 P.apply(dialog.mAlert) 代码段。
public void apply (AlertController dialog) {
if (mCustomTitleView != null ) {
dialog.setCustomTitle(mCustomTitleView);
} else {
if (mTitle != null ) {
dialog.setTitle(mTitle);
}
if (mIcon != null ) {
dialog.setIcon(mIcon);
}
if (mIconId >= 0 ) {
dialog.setIcon(mIconId);
}
if (mIconAttrId > 0 ) {
dialog.setIcon(dialog.getIconAttributeResId(mIconAttrId));
}
}
if (mMessage != null ) {
dialog.setMessage(mMessage);
}
if (mPositiveButtonText != null ) {
dialog.setButton(DialogInterface.BUTTON_POSITIVE, mPositiveButtonText,
mPositiveButtonListener, null );
}
if (mNegativeButtonText != null ) {
dialog.setButton(DialogInterface.BUTTON_NEGATIVE, mNegativeButtonText,
mNegativeButtonListener, null );
}
if (mNeutralButtonText != null ) {
dialog.setButton(DialogInterface.BUTTON_NEUTRAL, mNeutralButtonText,
mNeutralButtonListener, null );
}
if (mForceInverseBackground) {
dialog.setInverseBackgroundForced(true );
}
if ((mItems != null ) || (mCursor != null ) || (mAdapter != null )) {
createListView(dialog);
}
if (mView != null ) {
if (mViewSpacingSpecified) {
dialog.setView(mView, mViewSpacingLeft, mViewSpacingTop, mViewSpacingRight,
mViewSpacingBottom);
} else {
dialog.setView(mView);
}
}
}
实际上就是把 P 中的参数挨个的设置到 AlertController 中,也就是 AlertDialog 中的 mAlert 对象。从 AlertDialog 的各个 setter 方法中我们也可以看到,实际上也都是调用了 mAlert 对应的 setter 方法。在这里,Builder 同时扮演了上文中提到的 builder、ConcreteBuilder、Director 的角色,简化了 Builder 模式的设计。
在实际项目中的应用 我们可以采用系统已经提供好的 Builder 设计模式构建整个应用的万能 Dialog,代码可以参考系统的 AlertDialog。
public static class Builder {
private AlertController.AlertParams P;
public Builder (Context context) {
this (context, 0 );
}
public Builder (Context context, int themeResId) {
P = new AlertController .AlertParams();
P.themeResId = themeResId;
P.context = context;
}
public Builder setText (int viewId, CharSequence text) {
P.textArray.put(viewId, text);
return this ;
}
public Builder setOnClickListener (int viewId, View.OnClickListener listener) {
P.clickArray.put(viewId, listener);
return this ;
}
public Builder setContentView (int layoutId) {
P.view = null ;
P.layoutId = layoutId;
return this ;
}
public Builder setContentView (View view) {
P.layoutId = 0 ;
P.view = view;
return this ;
}
public Builder setCancelable (boolean cancelable) {
P.cancelable = cancelable;
return this ;
}
public Builder setOnCancelListener (OnCancelListener onCancelListener) {
P.onCancelListener = onCancelListener;
return this ;
}
public Builder setOnDismissListener (OnDismissListener onDismissListener) {
P.onDismissListener = onDismissListener;
return this ;
}
public BaseDialog create () {
final BaseDialog dialog = new BaseDialog (P.context, P.themeResId);
P.apply(dialog.mAlert);
dialog.setCancelable(P.cancelable);
if (P.cancelable) {
dialog.setCanceledOnTouchOutside(true );
}
dialog.setOnCancelListener(P.onCancelListener);
dialog.setOnDismissListener(P.onDismissListener);
if (P.onKeyListener != null ) {
dialog.setOnKeyListener(P.onKeyListener);
}
return dialog;
}
public BaseDialog show () {
final BaseDialog dialog = create();
dialog.show();
return dialog;
}
}
class AlertController {
private DialogViewHelper mViewHelper;
private BaseDialog mDialog;
private Window mWindow;
public AlertController (BaseDialog dialog, Window window) {
mDialog = dialog;
mWindow = window;
}
public BaseDialog getDialog () {
return mDialog;
}
public Window getWindow () {
return mWindow;
}
public DialogViewHelper getViewHelper () {
return mViewHelper;
}
public void setDialogViewHelper (DialogViewHelper viewHelper) {
this .mViewHelper = viewHelper;
}
public void setText (int viewId, CharSequence text) {
mViewHelper.setText(viewId, text);
}
public void setOnClickListener (int viewId, View.OnClickListener listener) {
mViewHelper.setOnClickListener(viewId, listener);
}
public <T extends View > T getView (int viewId) {
return mViewHelper.getView(viewId);
}
}
@Override
public void onClick (View v) {
BaseDialog dialog = new BaseDialog .Builder(this )
.setContentView(R.layout.detail_dialog).fullWith()
.fromBottom(false )
.show();
}
Builder 模式最佳实践与注意事项 在实际 Android 开发中应用 Builder 模式时,需要注意以下几点:
链式调用的返回值 :Builder 的所有 setter 方法应返回 this 实例,以便支持流畅的链式调用风格,提高代码可读性。
不可变性 :如果可能,建议将 Product 类中的属性设为 final,并在 Builder 中通过构造函数传入,确保对象一旦创建就不可修改,增强线程安全性。
默认值处理 :对于非必填参数,应在 Builder 中提供合理的默认值,避免客户端必须显式设置所有字段。
性能考量 :Builder 模式会创建额外的 Builder 对象,对于频繁创建且对内存敏感的场景,需权衡是否使用。但在 Android UI 初始化场景中,这种开销通常可忽略不计。
与工厂模式的区别 :Factory 模式侧重于创建对象,而 Builder 模式侧重于构建复杂对象的过程。如果对象构建步骤固定且复杂,优先选择 Builder。
总结 Builder 模式通过将复杂对象的创建过程封装起来,使得客户端不必知道产品内部组成的细节,同时允许对象通过多个步骤来创建,并且可以改变过程和选择需要的过程。在 Android 生态中,该模式极大地简化了 View 和 Dialog 的初始化代码,是开发者必须掌握的核心设计模式之一。
将一个复杂对象的创建过程封装起来,使得客户端不必知道产品内部组成的细节;
允许对象通过多个步骤来创建,并且可以改变过程和选择需要的过程;
产品的实现可以被替换,因为客户端只看到一个抽象的接口;
创建者独立,容易扩展。
会产生多余的 Builder 对象以及 Director 对象,消耗内存;
与工厂模式相比,采用 Builder 模式创建对象的客户,需要具备更多的领域知识。
相关免费在线工具 Keycode 信息 查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
Escape 与 Native 编解码 JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
JavaScript / HTML 格式化 使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
JavaScript 压缩与混淆 Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
Base64 字符串编码/解码 将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
Base64 文件转换器 将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online