一句话说透Android里面的建造者模式

207 阅读3分钟

一句话总结:
建造者模式就像「乐高说明书」—— 分步骤组装复杂对象,Android 里的 AlertDialogNotification 都用它告别构造器爆炸,让代码优雅如诗!


一、建造者模式在 Android 的经典应用

1. AlertDialog 的链式调用

// 使用建造者模式创建对话框  
AlertDialog dialog = new AlertDialog.Builder(context)  
    .setTitle("警告")  
    .setMessage("确定删除?")  
    .setPositiveButton("确定", (d, which) -> { /* 处理点击 */ })  
    .setNegativeButton("取消", null)  
    .create();  

dialog.show();  

源码实现

// frameworks/base/core/java/android/app/AlertDialog.java  
public static class Builder {  
    private final AlertController.AlertParams P;  

    public Builder(Context context) {  
        P = new AlertController.AlertParams(context);  
    }  

    public Builder setTitle(CharSequence title) {  
        P.mTitle = title;  
        return this;  
    }  

    public AlertDialog create() {  
        final AlertDialog dialog = new AlertDialog(P.mContext);  
        P.apply(dialog.mAlert); // 将参数应用到 AlertController  
        return dialog;  
    }  
}  

// 参数存储类  
public static class AlertParams {  
    public CharSequence mTitle;  
    public CharSequence mMessage;  
    // ... 其他 30+ 参数  
}  

设计亮点

  • 参数集中管理:所有配置项存储在 AlertParams 中
  • 构造延迟:直到 create() 才真正创建 AlertDialog 对象
  • 链式调用:每个 set 方法返回 this,提升可读性

二、底层设计原理剖析

1. 避免构造器爆炸(Telescoping Constructor)

传统构造器缺陷

// 传统方式需要多个重载构造器  
public AlertDialog(  
    Context context, String title, String message,  
    String positiveText, OnClickListener positiveListener,  
    String negativeText, OnClickListener negativeListener,  
    /* 更多参数... */ ) {  
    // 构造器臃肿难以维护  
}  

建造者模式优势

  • 可选参数灵活处理:30+ 参数中大部分有默认值
  • 强制必填参数:通过 Builder 构造函数实现(如 Builder(Context) 必须传 Context)

2. 参数校验与默认值

// 在 apply() 方法中处理默认逻辑  
public void apply(AlertController dialog) {  
    if (mTitle != null) dialog.setTitle(mTitle);  
    if (mMessage != null) dialog.setMessage(mMessage);  
    if (mPositiveButtonText != null) {  
        dialog.setButton(DialogInterface.BUTTON_POSITIVE,  
            mPositiveButtonText, mPositiveButtonListener);  
    }  
    // 设置默认取消行为  
    dialog.setOnCancelListener(mOnCancelListener);  
}  

3. 与系统资源的深度整合

// 通过 Context 获取主题样式  
public Builder(Context context) {  
    this(context, resolveDialogTheme(context, 0));  
}  

// 解析对话框主题  
static int resolveDialogTheme(Context context, int resid) {  
    if (resid == 0) return R.style.Theme_DeviceDefault_Dialog_Alert;  
    return resid;  
}  

三、建造者模式 vs 其他创建型模式

模式核心区别Android 案例
建造者模式分步构建复杂对象,参数灵活AlertDialog.Builder
工厂模式直接创建对象,关注产品类型BitmapFactory
原型模式通过克隆生成对象,避免重复初始化成本Parcelable 的 copy

四、高级应用:自定义建造者模式

1. 网络请求配置建造者

public class RequestBuilder {  
    private String url;  
    private Map<String, String> params;  
    private int timeout = 5000;  

    public RequestBuilder(String url) {  
        this.url = url;  
    }  

    public RequestBuilder addParam(String key, String value) {  
        if (params == null) params = new HashMap<>();  
        params.put(key, value);  
        return this;  
    }  

    public Request build() {  
        return new Request(url, params, timeout);  
    }  
}  

// 使用方式  
Request request = new RequestBuilder("https://api.example.com")  
    .addParam("page", "1")  
    .addParam("size", "20")  
    .build();  

2. 结合 Parcelable 实现高效传输

// 使用建造者模式构建跨进程数据  
public class User implements Parcelable {  
    private final String name;  
    private final int age;  

    public static class Builder {  
        private String name = "Anonymous";  
        private int age = 18;  

        public Builder setName(String name) {  
            this.name = name;  
            return this;  
        }  

        public User build() {  
            return new User(this);  
        }  
    }  

    private User(Builder builder) {  
        name = builder.name;  
        age = builder.age;  
    }  

    // Parcelable 实现...  
}  

五、源码中的隐藏技巧

1. 重用 Builder 配置

// 克隆现有配置创建新 Builder  
AlertDialog.Builder originalBuilder = new AlertDialog.Builder(context)  
    .setTitle("原始标题");  

AlertDialog.Builder newBuilder = new AlertDialog.Builder(context)  
    .applyFrom(originalBuilder) // 复制原有配置  
    .setMessage("新增内容");  

2. 内存优化技巧

// 使用后重置 Builder 避免内存泄漏  
public AlertDialog create() {  
    AlertDialog dialog = new AlertDialog(P.mContext);  
    P.apply(dialog.mAlert);  
    P.clear(); // 清空参数引用  
    return dialog;  
}  

六、总结口诀

构造复杂对象难,建造者来分步干
链式调用真优雅,参数灵活不爆炸
AlertDialog 是典范,自定义时照此办

使用场景建议

  1. 需要 4 个以上参数的复杂对象
  2. 参数之间存在依赖关系(如必须先设置类型才能设置其他参数)
  3. 需要支持多配置组合(如不同主题的通知)

注意事项

  1. 避免在 Builder 中保存 Context 引用(可能导致内存泄漏)
  2. 必要时对参数进行合法性校验(如检查 URL 格式)
  3. 线程安全考虑(若在多线程中使用需加同步锁)