设计模式(四)创建型:生成器模式详解

生成器模式(Builder Pattern)是 GoF 23 种设计模式中的核心创建型模式之一,其核心价值在于将一个复杂对象的构建过程与其表示分离,使得同样的构建过程可以创建不同的表示。它特别适用于构造过程稳定但组成部分多变、配置参数繁杂的对象,如配置文件解析器、SQL 查询构造器、HTML 文档生成器、API 请求对象等。生成器模式通过分步构建对象并支持方法链式调用(Fluent Interface),极大提升了代码的可读性与可维护性。在现代框架中,该模式已演变为“流式 API”设计的基础,是构建复杂对象的优雅解决方案。

一、生成器模式详细介绍

生成器模式解决的是“复杂对象构造”中的常见痛点:当一个类的构造函数参数过多(尤其是存在大量可选参数)时,直接使用构造器或 setter 方法会导致代码冗长、易错且难以阅读。生成器模式通过引入一个独立的“生成器”对象,将对象的构建过程分解为多个清晰的步骤,最终通过 build() 方法一次性完成对象的创建。

该模式涉及以下关键角色:

  • Product(产品类):表示被构建的复杂对象。它通常具有多个组成部分或配置项,且构造过程较为复杂。该类的构造函数通常是私有的,防止外部直接实例化。
  • Builder(抽象生成器接口或抽象类):声明构建 Product 所需的各个构建步骤(如 setPartA()setPartB()),以及一个返回最终产品对象的 build() 方法。它定义了构建过程的契约。
  • ConcreteBuilder(具体生成器):实现 Builder 接口,负责具体地执行每一步构建操作,并维护一个 Product 实例的引用。它可以根据需要提供不同的构建逻辑,从而生成不同配置的 Product。
  • Director(指挥者,可选):负责调用 Builder 对象的各个构建方法,按照特定顺序执行构建流程。在许多现代实现中,Director 的职责被客户端直接承担,通过链式调用完成构建。

生成器模式的核心优势在于:

  • 解耦构建过程与表示:构建逻辑集中在 Builder 中,Product 类无需关心如何被创建。
  • 支持分步构建:允许逐步设置对象的各个部分,尤其适合依赖外部数据或条件判断的场景。
  • 实现不可变对象:Product 可以在构建完成后设为不可变(Immutable),提升线程安全性。
  • 支持方法链式调用:每个构建方法返回 this,实现流畅的 API 风格(Fluent API),如 builder.setA("a").setB("b").build()

与“工厂模式”相比,生成器更关注“如何构建”一个对象,而工厂关注“创建哪一个”对象。生成器适用于构建过程复杂、参数多变的场景,而工厂适用于类型选择明确的场景。

二、生成器模式的UML表示

以下是生成器模式的标准 UML 类图:

implements
creates
uses
constructed by
Product
-partA: String
-partB: int
-partC: boolean
+getPartA()
+getPartB()
+getPartC()
-Product(builder: Builder)
«abstract»
Builder
+setPartA(partA: String)
+setPartB(partB: int)
+setPartC(partC: boolean)
+build()
ConcreteBuilder
-partA: String
-partB: int
-partC: boolean
+setPartA(partA: String)
+setPartB(partB: int)
+setPartC(partC: boolean)
+build()
Director
-builder: Builder
+constructMinimal()
+constructFull()

图解说明

  • Product 是最终要构建的复杂对象,其构造函数为私有,只能通过 Builder 创建。
  • Builder 是抽象生成器,定义了设置各个部分的方法和 build() 方法。
  • ConcreteBuilder 实现 Builder,维护构建过程中的中间状态,并在 build() 中使用这些状态创建 Product
  • Director(可选)封装了标准的构建流程,如“最小构建”或“完整构建”。
  • 客户端可通过 ConcreteBuilder 链式调用设置参数,最后调用 build() 获取最终对象。

三、一个简单的Java程序实例

以下是一个基于生成器模式的 Java 示例,模拟构建一个 Email 对象:

// 产品类:Email
final class Email {private final String from;private final String to;private final String subject;private final String body;private final boolean isHtml;private final boolean isPriority;// 私有构造函数,只能通过 Builder 创建private Email(Builder builder) {this.from = builder.from;this.to = builder.to;this.subject = builder.subject;this.body = builder.body;this.isHtml = builder.isHtml;this.isPriority = builder.isPriority;}// Getter 方法public String getFrom() { return from; }public String getTo() { return to; }public String getSubject() { return subject; }public String getBody() { return body; }public boolean isHtml() { return isHtml; }public boolean isPriority() { return isPriority; }@Overridepublic String toString() {return "Email{" +"from='" + from + '\'' +", to='" + to + '\'' +", subject='" + subject + '\'' +", body='" + body + '\'' +", isHtml=" + isHtml +", isPriority=" + isPriority +'}';}// 静态内部生成器类public static class Builder {private String from;private String to;private String subject;private String body;private boolean isHtml = false;private boolean isPriority = false;public Builder from(String from) {this.from = from;return this; // 支持链式调用}public Builder to(String to) {this.to = to;return this;}public Builder subject(String subject) {this.subject = subject;return this;}public Builder body(String body) {this.body = body;return this;}public Builder html(boolean html) {this.isHtml = html;return this;}public Builder priority(boolean priority) {this.isPriority = priority;return this;}// 构建最终对象public Email build() {// 可在此处添加参数校验if (from == null || to == null || subject == null || body == null) {throw new IllegalStateException("Required fields (from, to, subject, body) must be set.");}return new Email(this);}}
}// 客户端使用示例
public class BuilderPatternDemo {public static void main(String[] args) {// 使用生成器构建一个普通邮件Email email1 = new Email.Builder().from("alice@example.com").to("bob@example.com").subject("Hello").body("This is a plain text email.").html(false).priority(false).build();System.out.println(email1);// 使用生成器构建一个高优先级 HTML 邮件Email email2 = new Email.Builder().from("admin@system.com").to("user@company.com").subject("Urgent: System Alert").body("<h1>CRITICAL ALERT!</h1><p>Server is down.</p>").html(true).priority(true).build();System.out.println(email2);}
}

运行说明

  • Email 类是不可变的,所有字段在构建后不可更改。
  • Builder 类提供链式方法设置各个字段,最后调用 build() 创建 Email 实例。
  • 客户端代码清晰、易读,避免了长参数列表或 setter 的繁琐调用。
  • build() 方法中可加入参数校验,确保对象的完整性。

四、总结

生成器模式通过引入独立的构建过程,成功解决了复杂对象构造的难题:

  • 提升可读性:链式调用使代码像自然语言一样流畅。
  • 支持可选参数:无需为不同参数组合定义多个构造函数(避免“伸缩构造器反模式”)。
  • 保证对象完整性:可在 build() 阶段集中校验参数,防止创建不合法对象。
  • 支持不可变性:Product 可设计为不可变对象,增强线程安全。

但也存在缺点:

  • 增加类复杂度:需要为每个复杂类定义一个 Builder。
  • 不适合简单对象:对于字段少、构造简单的类,使用 Builder 反而增加冗余。

因此,应在“对象复杂度”与“代码简洁性”之间权衡使用。

架构师洞见:
生成器模式是现代 API 设计的“黄金标准”。在 Spring、OkHttp、JPA Criteria API 等主流框架中,流式构建(Fluent Builder)已成为标配。架构师应认识到:生成器不仅是创建对象的工具,更是一种提升开发者体验(DX)的设计哲学。它通过“意图清晰的 API”降低使用门槛,减少错误。未来,随着 DSL(领域特定语言)和代码生成技术的发展,生成器将进一步自动化——通过注解处理器或 APT 自动生成 Builder 代码,消除样板代码。掌握生成器模式,有助于设计出既强大又易用的内部组件与公共 API,是构建高质量、可维护系统的关键能力。在微服务配置、消息构造、查询构建等高频场景中,生成器模式的价值尤为突出。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/90926.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/90926.shtml
英文地址,请注明出处:http://en.pswp.cn/pingmian/90926.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

《Angular+Spring Boot:ERP前端采购销售库存协同架构解析》

基于Angular与Spring Boot构建的全栈ERP前端&#xff0c;绝非技术的简单叠加&#xff0c;而是通过深度融合两者特性&#xff0c;打造出兼具稳定性与灵活性的业务载体。Angular的组件化架构将复杂界面拆解为可复用的独立单元&#xff0c;依赖注入机制则让服务调用与数据流转条理…

Java 排序

文章目录排序插入排序分析希尔排序分析选择排序分析堆排序分析冒泡排序分析快速排序霍尔法分析挖坑法找基准前后指针法题目快排的优化三数取中法非递归实现快排归并排序分析非递归实现归并排序海量数据的排序非比较的排序计数排序分析基数排序桶排序排序 稳定的排序&#xff1…

日本IT就职面试|仪容礼仪篇分享建议

日系企業で好印象を与える「身だしなみ」と「面接マナー」ガイドこんにちは。 日系企業への就職・転職活動をされている方にとって、「第一印象」は合否を左右する大切なポイントですよね。実は、面接の評価は入室の瞬間から始まっていると言っても過言ではありません。 今回は…

英语听力口语词汇-8.美食类

1.crispy,crisp adj.酥脆的&#xff0c;易碎的 2.sweet adj.甜的 比如说chocolate is so sweet and delicious 3.chewy adj.难嚼的&#xff0c;难咽的 4.oatmeal n.燕麦粉 5.pickle n.泡菜 7.stir-fry v.炒菜 8.bacon n.咸肉&#xff0c;熏肉 9.yummy adj.美味可口的 1…

力扣7:整数反转

力扣7:整数反转题目思路代码题目 给你一个 32 位的有符号整数 x &#xff0c;返回将 x 中的数字部分反转后的结果。 如果反转后整数超过 32 位的有符号整数的范围 [−2^31, 2^31 − 1] &#xff0c;就返回 0。 思路 这道题我们可以分成两部分来做&#xff0c;一是完成反转二…

PWM信号控制电机

1&#xff1a;环境 STM32F103C8T6 KEIL5.38 2个电机 2个轮子 1个L298N STLINKV2 CH340 1个4位独立按键 杜邦线若干 2&#xff1a;代码 key.h #ifndef __KEY_H #define __KEY_H#include "stm32f10x.h"extern volatile uint8_t key_t ; extern volatile uint8_t …

开源赋能产业,生态共筑未来 | 开源科学计算与系统建模(openSCS)分论坛圆满举行

2025开放原子开源生态大会于7月23日-24日在北京国家会议中心召开。本届大会以“开源赋能产业&#xff0c;生态共筑未来”为主题&#xff0c;汇聚政、产、学、研、用、金、创、投等各领域开源力量&#xff0c;聚焦开源政策导向、生态发展趋势、开源产业实践&#xff0c;共探中国…

Android广播机制体系初识

Android广播机制体系大白话把Android的广播机制想象成小区里的“大喇叭”谁在喊话&#xff1f;任何App或系统都能当“大喇叭”&#xff0c;比如喊一嗓子“电量不足啦&#xff01;”&#xff08;这就是发送广播&#xff09;谁在听&#xff1f;其他App只要“竖起耳朵”&#xff0…

微信小程序点击输入框时,顶部导航栏被遮挡问题如何解决?

前言 不知道大家开发微信小程序的时候有没有遇到这么一个问题&#xff0c;就是在表单页面中&#xff0c;点击输入框后&#xff0c;输入框顶起会把顶部栏给遮挡住&#xff0c;如下图所示&#xff1a;遇到这种情况有没有解决的办法呢&#xff1f;能不能既将页面顶起&#xff0c;同…

通过具有一致性嵌入的大语言模型(LMMs)实现端到端乳腺癌放射治疗计划制定|文献速递-医学影像算法文献分享

Title题目End-to-end breast cancer radiotherapy planning via LMMs with consistencyembedding通过具有一致性嵌入的大语言模型&#xff08;LMMs&#xff09;实现端到端乳腺癌放射治疗计划制定01文献速递介绍近年来&#xff0c;受大型语言模型&#xff08;LLM&#xff09;启发…

vscode npm run build打包报ELIFECYCLE

npm run build打包报ELIFECYCLE 是内存溢出解决方案&#xff1a;修改build脚本 &#xff1a;"build": "node --max_old_space_size4096 node_modules/vue/cli-service/bin/vue-cli-service.js build",

【lucene】BlockMaxConjunctionScore

BlockMaxConjunctionScorer 是 Lucene 8.5 引入的一个高性能交集打分器&#xff08;conjunction scorer&#xff09;&#xff0c;专门用于处理 多条件“与”查询&#xff08;AND 查询&#xff09; 的场景。它基于 Block-Max WAND&#xff08;BMW&#xff09;算法&#xff0c;可…

Androidstudio 上传当前module 或本地jar包到maven服务器。

1.设置gradle版本到8.0 gradle-wrapper.properties文件中设置&#xff1a; distributionUrlhttps\://mirrors.aliyun.com/macports/distfiles/gradle/gradle-8.0-bin.zip 2.设置项目根目录build.gradle 设置agp版本和maven插件版本&#xff08;和gralde版本有对应关系&#xff…

Python动态规划:从基础到高阶优化的全面指南

动态规划&#xff08;Dynamic Programming&#xff09;是解决复杂优化问题的核心技术&#xff0c;也是算法领域的明珠。本文将深入探讨Python实现动态规划的全方位技术&#xff0c;涵盖基础概念、经典问题、优化技巧和实际工程应用&#xff0c;带您掌握这一强大工具的精髓。一、…

视觉大模型部署实践篇(Docker+dify+ollama安装)

一、概述 目的:实现一个本地化部署的大模型,通过工作流对图像进行一些处理。基于此,我选择了Docker+Dify+Ollama的部署。 具体实现逻辑:Docker来运行dify,dify用来绘制大模型的工作流或者rag等,Ollama用来部署本地大模型,dify调用Ollama部署的大模型进行推理。 二、Dock…

服务器启动日志等级

目录 标准日志等级 服务器启动阶段常见日志 日志配置建议 常见服务器/工具的日志等级配置方式 ET框架 Apache/Nginx 等 Web 服务器 Docker 容器 服务器启动过程中的日志等级是帮助开发者和运维人员理解系统状态的重要工具。常见的日志等级及其含义如下&#xff1a; 标准…

linux_centos7安装jdk8_采用jdk安装包安装

你问我为什么不用yum? 我yum安装不了&#xff0c;我也解决不了qwq. 文章目录一.下载安装包1.找到安装包下载位置2.上传安装包到linux3.解压jdk安装包4.配置环境一.下载安装包 1.找到安装包下载位置 去官网找到你要下载jdk版本&#xff1a; Oracle官网 下面演示安装jdk8的&am…

Linux驱动23 --- RkMedia 使用

目录 一、上电自动挂载 二、RkMedia 2.1 认识 RkMedia rtsp rtmp RTSP 和 RTMP 的选择 2.2 安装 VLC 2.2 RkMedia 例程使用 一、上电自动挂载 cd /etc/init.d/ vi Smyprofile.sh 添加这个内容 #!/bin/sh ifconfig eth0 192.168.66.88 mount -t nfs 192.168.66.66…

Linux:线程同步与线程互斥

线程互斥竞态条件当多个线程&#xff08;或进程&#xff09;并发访问和操作同一个共享资源&#xff08;如变量、文件、数据库记录等&#xff09;时&#xff0c;最终的结果依赖于这些线程执行的相对时序&#xff08;即谁在什么时候执行了哪条指令&#xff09;。 由于操作系统调度…

HTML 常用标签速查表

HTML 常用标签速查表 &#x1f9f1; 结构类标签 标签含义用途说明<html>HTML文档根元素所有HTML内容的根节点<head>头部信息放置元信息&#xff0c;如标题、引入CSS/JS等<body>页面内容主体所有可视内容的容器&#x1f4dd; 文本与标题标签 标签含义用途说…