一、故事解说:组装电脑的流水线
想象你去电脑城组装电脑,流程如下:
-
告诉店员需求:你说 “我要一台游戏电脑,显卡要 RTX4080,内存 32G”,店员不会直接扔给你一堆零件,而是按步骤组装。
-
流水线分工:
- Builder( builder 类) :像不同的工人,负责装主板、插内存、装显卡等具体步骤;
- Director(指挥者) :像流水线班长,按顺序调用工人的动作(先装主板,再插内存,最后装显卡);
- Product(产品) :最终组装好的电脑。
-
灵活定制:不同需求(游戏电脑、办公电脑)只需换 Builder,流水线(Director)流程不变。
二、构建者模式核心角色
- Builder:定义构建产品各部分的方法(如
buildCPU()、buildMemory()); - Director:定义构建顺序(如先装 CPU,再装内存);
- Product:最终复杂对象(如电脑)。
三、Android 常用构建者案例与实现
案例 1:AlertDialog.Builder(最经典的 Android 构建者)
java
// Product:AlertDialog
public class AlertDialog {
private Context context;
private String title;
private String message;
private String positiveButtonText;
private DialogInterface.OnClickListener positiveButtonClickListener;
// 省略其他属性(图标、Negative按钮等)
// 构造函数私有,只能通过Builder创建
private AlertDialog(Builder builder) {
this.context = builder.context;
this.title = builder.title;
this.message = builder.message;
this.positiveButtonText = builder.positiveButtonText;
this.positiveButtonClickListener = builder.positiveButtonClickListener;
}
// Builder类:构建AlertDialog的各个部分
public static class Builder {
private Context context;
private String title;
private String message;
private String positiveButtonText;
private DialogInterface.OnClickListener positiveButtonClickListener;
public Builder(Context context) {
this.context = context;
}
// 构建各部分的方法(链式调用)
public Builder setTitle(String title) {
this.title = title;
return this; // 返回自身,支持链式调用
}
public Builder setMessage(String message) {
this.message = message;
return this;
}
public Builder setPositiveButton(String text, DialogInterface.OnClickListener listener) {
this.positiveButtonText = text;
this.positiveButtonClickListener = listener;
return this;
}
// 最后一步:创建Product
public AlertDialog create() {
return new AlertDialog(this);
}
// 直接显示对话框(简化版Director)
public AlertDialog show() {
AlertDialog dialog = create();
dialog.show();
return dialog;
}
}
}
// 使用方式
new AlertDialog.Builder(this)
.setTitle("提示")
.setMessage("确定要退出吗?")
.setPositiveButton("确定", (dialog, which) -> finish())
.setNegativeButton("取消", null)
.show();
优点:
-
链式调用直观:代码像自然语言(“设置标题→设置消息→设置按钮”);
-
必填参数明确:Builder 构造函数强制传入 Context,避免空指针;
-
扩展性好:新增属性只需在 Builder 中添加方法,不影响原有逻辑。
缺点:
- 类数量增加:每个 Product 对应一个 Builder,项目庞大时类数翻倍;
- 构建过程不可见:Director 逻辑嵌入在 Builder 的
show()中,复杂流程难定制。
案例 2:Notification.Builder(Android 通知构建者)
java
// Product:Notification
public class Notification {
private Context context;
private int smallIcon;
private CharSequence title;
private CharSequence text;
private PendingIntent contentIntent;
// 省略其他属性(大图标、进度条等)
private Notification(Builder builder) {
this.context = builder.context;
this.smallIcon = builder.smallIcon;
this.title = builder.title;
this.text = builder.text;
this.contentIntent = builder.contentIntent;
}
// Builder类
public static class Builder {
private Context context;
private int smallIcon;
private CharSequence title;
private CharSequence text;
private PendingIntent contentIntent;
public Builder(Context context, String channelId) {
this.context = context;
// Android 8.0+必须指定通知渠道
NotificationManager manager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(
channelId, "渠道名称", NotificationManager.IMPORTANCE_DEFAULT);
manager.createNotificationChannel(channel);
}
}
public Builder setSmallIcon(int icon) {
this.smallIcon = icon;
return this;
}
public Builder setContentTitle(CharSequence title) {
this.title = title;
return this;
}
public Builder setContentText(CharSequence text) {
this.text = text;
return this;
}
public Builder setContentIntent(PendingIntent intent) {
this.contentIntent = intent;
return this;
}
public Notification build() {
return new Notification(this);
}
}
}
// 使用方式
Notification notification = new Notification.Builder(this, "channel_id")
.setSmallIcon(R.drawable.ic_notify)
.setContentTitle("新消息")
.setContentText("您有10条未读消息")
.setContentIntent(clickIntent)
.build();
notificationManager.notify(1, notification);
优点:
-
分步骤构建复杂对象:通知包含图标、文字、点击事件等 10 + 属性,构建者模式避免参数混乱;
-
默认值合理:未设置的属性(如大图标)使用系统默认,降低使用门槛;
-
版本兼容:Builder 内部处理 Android 8.0 + 的通知渠道适配,调用方无感知。
缺点:
- 参数校验延迟:直到
build()才发现必填参数缺失(如未设置 smallIcon 会报错); - 构建过程耦合:Builder 内部包含版本兼容逻辑,违反 “单一职责原则”。
案例 3:OkHttpClient.Builder(网络请求客户端构建者)
java
// Product:OkHttpClient
public class OkHttpClient {
private final Dispatcher dispatcher;
private final List<Interceptor> interceptors;
private final List<Interceptor> networkInterceptors;
private final Proxy proxy;
// 省略其他属性(连接超时、读写超时等)
private OkHttpClient(Builder builder) {
this.dispatcher = builder.dispatcher;
this.interceptors = builder.interceptors;
this.networkInterceptors = builder.networkInterceptors;
this.proxy = builder.proxy;
}
// Builder类
public static class Builder {
private Dispatcher dispatcher;
private final List<Interceptor> interceptors = new ArrayList<>();
private final List<Interceptor> networkInterceptors = new ArrayList<>();
private Proxy proxy = Proxy.NO_PROXY;
private int connectTimeout = 10; // 默认10秒
private int readTimeout = 10;
private int writeTimeout = 10;
public Builder() {
this.dispatcher = new Dispatcher();
}
public Builder connectTimeout(int timeout, TimeUnit unit) {
this.connectTimeout = (int) unit.toSeconds(timeout);
return this;
}
public Builder addInterceptor(Interceptor interceptor) {
interceptors.add(interceptor);
return this;
}
public Builder addNetworkInterceptor(Interceptor interceptor) {
networkInterceptors.add(interceptor);
return this;
}
public Builder proxy(Proxy proxy) {
this.proxy = proxy;
return this;
}
public OkHttpClient build() {
// 校验参数
if (dispatcher == null) {
throw new IllegalStateException("dispatcher required");
}
return new OkHttpClient(this);
}
}
}
// 使用方式
OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(15, TimeUnit.SECONDS) // 连接超时15秒
.readTimeout(20, TimeUnit.SECONDS) // 读取超时20秒
.addInterceptor(new LoggingInterceptor()) // 添加日志拦截器
.addNetworkInterceptor(new CacheInterceptor()) // 添加网络缓存拦截器
.build();
优点:
-
灵活扩展:通过
addInterceptor可无限添加自定义功能(日志、缓存、token 拦截等); -
默认值合理:提供常用默认参数(10 秒超时),简单场景无需配置;
-
线程安全:Builder 构建过程是线程安全的,最终 OkHttpClient 实例也是不可变对象。
缺点:
- 参数关联性弱:部分参数(如超时时间)之间的关联性需要调用方自己保证;
- 构建成本高:每个 OkHttpClient 实例包含独立的拦截器列表,频繁创建会消耗内存。
四、构建者模式的适用场景与总结
适用场景:
- 对象构建复杂:如 AlertDialog 包含 10 + 属性,参数组合多;
- 需要多配置版本:如通知可配置为普通通知、进度通知、悬挂通知;
- 构建过程需分步骤:如 OkHttpClient 需先配置超时,再添加拦截器。
核心优点:
- 解耦构建与表示:Director(构建流程)和 Product(最终对象)分离,方便修改流程;
- 链式调用易读:代码如 “设置 A→设置 B→设置 C”,比参数列表更清晰;
- 强制分步构建:避免 “半初始化” 对象(必须按步骤完成所有必要配置)。
核心缺点:
- 类数量翻倍:每个 Product 对应一个 Builder,小型项目可能 “小题大做”;
- 构建过程隐藏:复杂流程的优化(如并行构建)难以实现,因为流程嵌入在 Builder 中。
Android 中的最佳实践:
-
优先使用系统 Builder:如 AlertDialog.Builder、Notification.Builder,避免重复造轮子;
-
自定义 Builder 时:
- 在 Builder 构造函数中强制传入必填参数;
- 在
build()方法中做参数校验; - 使用不可变对象(Product 属性用 final 修饰),避免构建后被修改。### 一、构建者模式:用组装汽车的故事理解
想象你要定制一辆汽车,有很多可选配置:
-
发动机:燃油、电动、混动?
-
颜色:红色、蓝色、黑色?
-
内饰:真皮、织物、仿皮?
-
附加功能:自动驾驶、座椅加热、全景天窗?
如果直接去汽车工厂(传统构造函数),可能需要这样的代码:
java
Car car = new Car("燃油发动机", "红色", "真皮", true, false, true);
// 参数太多,顺序容易记混,还得为不需要的功能传null
构建者模式就像找一个 “汽车定制顾问”:
java
Car car = new CarBuilder()
.setEngine("电动")
.setColor("蓝色")
.setInterior("仿皮")
.addAutopilot()
.build(); // 按需配置,最后一键生成
核心优点:
- 链式调用:代码更易读,参数顺序不敏感;
- 可选配置:不需要的参数可以不设置,避免传 null;
- 不可变对象:构建完成后对象状态不可修改(通过 private final 字段)。
二、Android 常用构建者案例实现
1. 自定义 Dialog(类似 AlertDialog)
java
// 产品类:Dialog
public class CustomDialog {
private final Context context;
private final String title;
private final String message;
private final String positiveText;
private final String negativeText;
private final OnClickListener positiveListener;
private final OnClickListener negativeListener;
private final boolean cancelable;
private CustomDialog(Builder builder) {
this.context = builder.context;
this.title = builder.title;
this.message = builder.message;
this.positiveText = builder.positiveText;
this.negativeText = builder.negativeText;
this.positiveListener = builder.positiveListener;
this.negativeListener = builder.negativeListener;
this.cancelable = builder.cancelable;
}
// 显示对话框
public void show() {
// 实际实现:创建并显示Dialog
Log.d("CustomDialog", "Showing dialog with title: " + title);
}
// 构建者类
public static class Builder {
private final Context context;
private String title;
private String message;
private String positiveText = "确定";
private String negativeText = "取消";
private OnClickListener positiveListener;
private OnClickListener negativeListener;
private boolean cancelable = true;
public Builder(Context context) {
this.context = context;
}
public Builder setTitle(String title) {
this.title = title;
return this;
}
public Builder setMessage(String message) {
this.message = message;
return this;
}
public Builder setPositiveButton(String text, OnClickListener listener) {
this.positiveText = text;
this.positiveListener = listener;
return this;
}
public Builder setNegativeButton(String text, OnClickListener listener) {
this.negativeText = text;
this.negativeListener = listener;
return this;
}
public Builder setCancelable(boolean cancelable) {
this.cancelable = cancelable;
return this;
}
public CustomDialog build() {
return new CustomDialog(this);
}
}
}
// 使用示例
CustomDialog dialog = new CustomDialog.Builder(context)
.setTitle("提示")
.setMessage("确定要删除这条数据吗?")
.setPositiveButton("确认", v -> { /* 处理确认逻辑 */ })
.setNegativeButton("取消", null)
.setCancelable(false)
.build();
dialog.show();
优点:
-
可选参数灵活(如不需要标题可以不设置);
-
链式调用更直观;
-
避免创建过多构造函数重载。
缺点:
- 代码量增加(需要额外的 Builder 类);
- 只能用于需要多参数配置的场景。
2. 网络请求参数构建(类似 OkHttp 的 Request.Builder)
java
// 产品类:HttpRequest
public class HttpRequest {
private final String url;
private final String method;
private final Map<String, String> headers;
private final Map<String, String> params;
private final String body;
private final int timeout;
private HttpRequest(Builder builder) {
this.url = builder.url;
this.method = builder.method;
this.headers = builder.headers;
this.params = builder.params;
this.body = builder.body;
this.timeout = builder.timeout;
}
// 发送请求
public void execute() {
// 实际实现:发送网络请求
Log.d("HttpRequest", "Executing " + method + " request to " + url);
}
// 构建者类
public static class Builder {
private final String url;
private String method = "GET";
private Map<String, String> headers = new HashMap<>();
private Map<String, String> params = new HashMap<>();
private String body;
private int timeout = 30000; // 默认30秒超时
public Builder(String url) {
this.url = url;
}
public Builder setMethod(String method) {
this.method = method;
return this;
}
public Builder addHeader(String key, String value) {
this.headers.put(key, value);
return this;
}
public Builder addParam(String key, String value) {
this.params.put(key, value);
return this;
}
public Builder setBody(String body) {
this.body = body;
return this;
}
public Builder setTimeout(int timeout) {
this.timeout = timeout;
return this;
}
public HttpRequest build() {
// 可以添加参数校验逻辑
if (!Arrays.asList("GET", "POST", "PUT", "DELETE").contains(method)) {
throw new IllegalArgumentException("Invalid HTTP method: " + method);
}
return new HttpRequest(this);
}
}
}
// 使用示例
HttpRequest request = new HttpRequest.Builder("https://api.example.com/data")
.setMethod("POST")
.addHeader("Content-Type", "application/json")
.addParam("page", "1")
.addParam("size", "20")
.setBody("{"key": "value"}")
.setTimeout(60000)
.build();
request.execute();
优点:
-
参数配置灵活(如不需要 body 可以不传);
-
可以添加参数校验(如 build () 中检查 method 合法性);
-
支持默认值(如 timeout 默认 30 秒)。
缺点:
- 对于简单请求(如只有 URL 的 GET 请求),显得冗余;
- 构建过程中无法中途修改已设置的参数(如需修改需重新创建 Builder)。
3. 自定义 View 属性配置(类似 View 的 LayoutParams)
java
// 产品类:自定义View
public class CustomView extends View {
private int textSize;
private int textColor;
private String text;
private Drawable background;
private int padding;
public CustomView(Context context) {
this(context, null);
}
public CustomView(Context context, AttributeSet attrs) {
super(context, attrs);
// 解析XML属性
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.CustomView);
textSize = ta.getDimensionPixelSize(R.styleable.CustomView_textSize, 16);
textColor = ta.getColor(R.styleable.CustomView_textColor, Color.BLACK);
text = ta.getString(R.styleable.CustomView_text);
ta.recycle();
}
// 使用构建者更新属性
public void update(Builder builder) {
if (builder.textSize != -1) this.textSize = builder.textSize;
if (builder.textColor != 0) this.textColor = builder.textColor;
if (builder.text != null) this.text = builder.text;
if (builder.background != null) this.background = builder.background;
if (builder.padding != -1) this.padding = builder.padding;
invalidate(); // 刷新视图
}
// 构建者类
public static class Builder {
private int textSize = -1;
private int textColor = 0;
private String text;
private Drawable background;
private int padding = -1;
public Builder setTextSize(int textSize) {
this.textSize = textSize;
return this;
}
public Builder setTextColor(int textColor) {
this.textColor = textColor;
return this;
}
public Builder setText(String text) {
this.text = text;
return this;
}
public Builder setBackground(Drawable background) {
this.background = background;
return this;
}
public Builder setPadding(int padding) {
this.padding = padding;
return this;
}
public void applyTo(CustomView view) {
view.update(this);
}
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// 绘制逻辑...
}
}
// 使用示例
CustomView view = findViewById(R.id.customView);
new CustomView.Builder()
.setText("Hello Builder")
.setTextColor(Color.RED)
.setPadding(16)
.applyTo(view);
优点:
-
可以选择性更新部分属性(如只更新 text,不影响其他属性);
-
避免在 View 中定义大量 setter 方法;
-
可以在运行时动态修改 View 属性。
缺点:
- 需要在 View 内部添加额外的 update () 方法;
- 不适用于一次性初始化(XML 布局中无法直接使用)。
三、构建者模式优缺点总结
| 优点 | 缺点 |
|---|---|
| 链式调用,代码更易读 | 需要创建额外的 Builder 类,代码量增加 |
| 可选参数配置,无需传 null | 对于简单对象(参数少)显得冗余 |
| 支持参数校验(在 build () 中检查) | 构建过程中无法中途修改已设置的参数 |
| 生成不可变对象(通过 private final) | 不适用于参数经常变化的场景 |
| 支持默认值 |
四、使用场景建议
推荐在以下情况使用构建者模式:
-
参数超过 3 个,尤其是包含可选参数时;
-
对象需要不可变(构建后状态不能修改);
-
参数配置复杂,需要进行校验或依赖关系处理(如 A 参数存在时 B 必须存在);
-
同一个对象需要多种配置组合(如 Dialog 可能有标题 + 消息,或只有消息)。
Android 系统中,构建者模式广泛应用于:
-
AlertDialog.Builder -
Notification.Builder -
Retrofit的Request.Builder -
OkHttp的Request.Builder和OkHttpClient.Builder
通过构建者模式,可以让代码更简洁、更安全,同时提升 API 的易用性。