当前位置: 首页 > news >正文

深入解析建造者模式:告别“伸缩构造器”,优雅构建复杂对象

深入解析建造者模式:告别“伸缩构造器”,优雅构建复杂对象

在软件开发中,你是否曾为创建一个包含众多可选参数、构造逻辑复杂的对象而感到头疼?当构造函数参数列表越来越长,代码变得难以阅读和维护时,你就遇到了经典的“伸缩构造器反模式”。今天,我们将深入探讨一种优雅的解决方案——建造者模式。它不仅能够将对象的构建与表示分离,还能让代码更具可读性、灵活性和可维护性。无论你是使用Java、Python、Go还是C++,理解建造者模式都将极大地提升你的代码设计能力。

一、建造者模式的核心思想与价值

建造者模式(Builder Pattern)是一种创建型设计模式,其核心目标是将一个复杂对象的构建过程与其最终表示分离开来。这样,同一个构建过程可以创造出不同表现形式的产品。想象一下建造房屋:建筑师(指挥者)使用同一套施工蓝图(构建过程),但根据不同的承包商(具体建造者)和材料,最终可以建成中式庭院、现代别墅或欧式城堡等不同风格的房屋(产品)。

:指通过构造器实现对象构建参数初始化,如果对象属性比较多,导致构造器的参数个数不可控。

该模式的价值在于:

  • 解耦构建与表示:客户端无需知晓对象内部复杂的组装细节。
  • 精细控制构建过程:将构建步骤分解,使流程更清晰。
  • 提升代码可读性:通过链式调用等方法,使对象创建代码像自然语言一样流畅。
  • 支持开闭原则:增加新的产品表示(新的具体建造者)时,无需修改现有代码。

在这里插入图片描述

二、模式结构:四大角色各司其职

建造者模式通常包含四个关键角色,它们协同工作,共同完成复杂对象的创建。

在这里插入图片描述

  1. 产品(Product):即 Product(产品角色)。它是最终要构建的复杂对象,通常包含多个部件。例如,一个“电脑”产品可能由CPU、内存、硬盘等部件组成。
  2. 抽象建造者(Builder):即 Builder(抽象建造者)。它定义了创建产品各个部件的抽象接口(Builder)。通常包含两类方法:一类是像 buildPartXXXX() 这样的“部件构建方法”,另一类是像 build() 这样的“最终产品获取方法”。它为所有具体建造者制定了“施工规范”。
  3. 具体建造者(ConcreteBuilder):即 ConcreteBuilder(具体建造者)。它实现了 Builder 接口,负责具体部件的构造和装配。例如,“游戏电脑建造者”和“办公电脑建造者”会以不同的方式实现组装CPU和内存的方法。
  4. 指挥者(Director):即 Director(指挥者)。它是构建过程的“导演”,负责调用建造者的方法,按特定顺序或逻辑一步步构建产品。客户端通常只与指挥者交互,通过它来获得最终产品。

简单说就是:

  • 如果用户通过创建对象,创建过程是由的方法规定的,且是规定死的,一般不做修改。用户可以通过配置文件(或者反射)选择不同的作为(具体创建者),进而通过多态传参进入方法,然后按照进行构造,只不过构建过程是一样的,而创建出的产品不同(例子见下面的)
  • 有时候为了提高构建灵活性,提供更丰富的组合,可以不使用,而是把写到复杂对象里面,让用户自己指定调用初始化的顺序以及选择使用哪些方法初始化(例子见下面的)

三、经典实现:基于指挥者的标准模式

让我们通过一个具体的例子来理解标准建造者模式的工作流程。假设我们要构建一个复杂的“角色”对象,它包含职业、发型、盔甲等属性。

首先,我们定义产品类:

@Getter
@Setter
@ToString
public class Human {
private String type;
private String region;
}

接着,定义抽象建造者及其具体实现。抽象建造者声明了构建各个部件和获取产品的方法:

public abstract class HumanBuilder {
protected Human human = new Human();
public abstract HumanBuilder buildType();
public abstract HumanBuilder buildRegion();
public Human build() {
//对象复制
Human target = new Human();
target.setType(human.getType());
target.setRegion(human.getRegion());
return target;
}
}

然后,我们实现两个具体建造者,比如一个构建“英雄”,一个构建“恶棍”:

public class YellowManBuilder extends HumanBuilder {
@Override
public HumanBuilder buildType() {
human.setType("黄种人");
return this;
}
@Override
public HumanBuilder buildRegion() {
human.setRegion("华夏");
return this;
}
}
public class WhiteManBuilder extends HumanBuilder {
@Override
public HumanBuilder buildType() {
human.setType("白种人");
return this;
}
@Override
public HumanBuilder buildRegion() {
human.setRegion("欧洲");
return this;
}
}

关键的指挥者类负责控制构建流程:

public class BlackManBuilder extends HumanBuilder {
@Override
public HumanBuilder buildType() {
//继承了父类创建的具体Human对象
human.setType("黑人");
return this;//返回当前对象
}
@Override
public HumanBuilder buildRegion() {
human.setRegion("非洲");
return this;//返回当前对象
}
}

最后,客户端代码通过配置和反射机制动态决定使用哪个建造者,并委托指挥者完成构建:

@AllArgsConstructor
public class HumanDirector {
private HumanBuilder builder;
public Human construct(){
return builder
.buildType()
.buildRegion()
.build();
}
}
bp1=com.zeroone.star.builder.ex1.builder.YellowManBuilder
public class App {
public static void main(String[] args) throws Exception {
//加载配置
ResourceBundle conf = ResourceBundle.getBundle("conf");
String bp1 = conf.getString("bp1");
//构建Builder
HumanBuilder builder = (HumanBuilder) Class.forName(bp1).newInstance();
//创建指挥者
HumanDirector director = new HumanDirector(builder);
//创建人类
Human human = director.construct();
System.out.println(human);
}
}

这种实现方式的优点是结构清晰,职责分离彻底,特别适合构建过程复杂且步骤固定的场景。在Java、C++等静态语言中应用广泛。

在这里插入图片描述

[AFFILIATE_SLOT_1]

四、简化变体:链式调用与静态内部类建造者

在实际开发中,尤其是使用Python、JavaScript等动态语言时,我们常常会使用一种更简洁的变体——链式建造者。它通常省略了指挥者角色,并将建造者作为产品类的静态内部类。这种方式在Java中因Lombok库的@Builder注解而流行,在Go语言中通过函数选项模式(Functional Options)实现类似效果。

在这里插入图片描述

其核心是产品类内部包含一个静态建造者类,建造者提供设置各个属性的方法(通常返回建造者自身以支持链式调用),最后通过一个`build()`方法返回构建好的产品。

以下是产品类及其内部建造者的实现:

@Getter
@ToString
public class Hero {
private String name;
private Profession profession;
private Armor armor;
private HairColor hairColor;
private HairType hairType;
private Weapon weapon;
public static class Builder {
private String name;
private Profession profession;
private Armor armor;
private HairColor hairColor;
private HairType hairType;
private Weapon weapon;
//构造函数
public Builder(String name, Profession profession) {
this.name = name;
this.profession = profession;
}
//具体方法
public Builder withArmor(Armor armor){
this.armor = armor;
return this;//返回当前对象
}
public Builder withHairColor(HairColor hairColor){
this.hairColor = hairColor;
return this;
}
public Builder withHairType(HairType hairType){
this.hairType = hairType;
return this;
}
public Builder withWeapon(Weapon weapon){
this.weapon = weapon;
return this;
}
//build方法
public Hero build(){
return new Hero(this);
}
}
private Hero(Builder builder) {
this.name = builder.name;
this.profession = builder.profession;
this.armor = builder.armor;
this.hairColor = builder.hairColor;
this.hairType = builder.hairType;
this.weapon = builder.weapon;
}
}

相关的枚举或值对象:

public class Armor {
}
public class HairColor {
}
......

客户端使用起来极其简洁直观:

public class App {
public static void main(String[] args) {
//类名.内部类名的方式“实例化”建造者
Hero hero = new Hero.Builder("阿狸", new Profession())//初始化建造者:执行了定义的Builder(String name, Profession profession) 构造函数。
.withArmor(new Armor())//"安装零件"
.withWeapon(new Weapon())
.build();//最后调用创建者的build方法,把整个Builder对象作为参数,传递给了 Hero 的私有构造函数。做了属性拷贝
System.out.println(hero);
}
}

总结一下:

  • 实现1这种方式,很适合:相同的步骤,产生不同的具体产品。适用于"标准化"生产

  • 而相比于实现1,实现2的方式更灵活,没有外部的 (指挥者),调用者可以任意组合,选任意的属性个数或者打乱顺序都可以。适用于按需配置对象。

这种模式的优点是API非常友好,创建对象的代码就像在配置一个对象,一目了然。许多现代框架和库(如Lombok)都采用了这种方式。

五、实战对比、适用场景与最佳实践

建造者模式 vs. 工厂模式:两者都是创建型模式,但关注点不同。工厂模式(特别是抽象工厂)关注的是“创建什么产品族”,而建造者模式关注的是“如何一步步组装一个复杂产品”。工厂是“即拿即用”,建造者是“按需定制”。

主要优点

  • 构建与表示分离:客户端代码与复杂对象的内部结构解耦。
  • 构建过程可控:指挥者可以精细控制每一步,甚至构建中间状态。
  • 符合开闭原则:新增产品表示(新的ConcreteBuilder)非常容易。
  • 提升可读性:链式调用使代码意图更清晰,尤其在Python、JavaScript中。

主要缺点与注意事项

  • ⚠️ 适用范围有限:产品之间必须有较多的共同点。如果产品差异极大,建造者模式会显得冗余。
  • ⚠️ 可能增加类数量:每个具体产品都可能对应一个建造者类,在小型项目中可能增加复杂度。
  • ⚠️ 产品需可变:建造者通常要求产品部件在构建阶段是可设置的。

经典应用案例

  • Java: StringBuilder, Lombok的@Builder注解。
  • Go: 函数选项模式(Functional Options),用于配置结构体。
  • JavaScript/TypeScript: 库的配置对象构建,如Axios、Three.js的配置。
  • C++: 流式输出操作符`<<`的重载,可以看作一种链式构建。

以下是Lombok @Builder的简洁示例:

@Builder  // 自动生成 Builder 模式的所有代码
@ToString
public class Human {
private String type;
private String region;
}
public class App {
public static void main(String[] args) {
//随心所欲的组装
Human blackMan = Human.builder()
.region("非洲")
.type("黑人")
.build();
Human whiteMan = Human.builder()
.type("白人")
.region("欧洲")
.build();
System.out.println(blackMan);
}
}
[AFFILIATE_SLOT_2]

六、总结

建造者模式是解决复杂对象创建问题的利器。当你面对一个拥有众多可选参数、构造逻辑繁琐、或者需要分步构建的对象时,请考虑使用建造者模式。对于标准的分步构建场景,采用“产品-抽象建造者-具体建造者-指挥者”的经典结构;对于追求API简洁和流畅性的场景,可以采用链式调用与静态内部类的简化变体。掌握建造者模式,你将能写出更清晰、更灵活、更易于维护的对象创建代码,从容应对各种复杂的业务对象构建需求。

伸缩性构造的反模式DirectorDirectorconstruct()ConcreteBuilderBuilderconstruct()不同子类的不同buildPartXXXX()实现1DirectorBuilder实现2Director
http://www.jsqmd.com/news/593815/

相关文章:

  • 15人开发团队的远程办公“通关秘籍”——飞将让内网互访又快又稳
  • P16185 [LBA-OI R1 B] 战术突破 题解
  • Steam Depot清单自动化工具:Onekey实现游戏数据高效管理的完整方案
  • 智能图片采集工具Image-Downloader:从需求到落地的完整指南
  • 【C++第二十五章】智能指针
  • SpringBoot + 本地事务表 + 定时扫描补偿:轻量级方案实现最终一致性,无中间件依赖
  • 计算机毕业设计:Python二手车智能数据分析与可视化决策平台 Django框架 可视化 线性回归 数据分析 机器学习 深度学习 AI 大模型(建议收藏)✅
  • 用 Win32 API MCP Tool 打通桌面环境控制链路,兼谈 DМχΑРΙ
  • Obsidian Tag Summary插件完全指南:用标签玩出笔记系统的“黑科技感“
  • 20252820 2024-2025-2 《网络攻防实践》第4次作业
  • YimMenu终极指南:5分钟学会GTA5最强安全增强工具
  • JAVA重点基础、进阶知识及易错点总结(34)注解基础(Annotation)
  • OpenCV直线检测避坑指南:HoughLinesP参数调优实战(Python版)
  • Go语言的缓存策略与实现
  • S7-200 MCGS 基于PLC的小型水厂恒压供水系统 带解释的梯形图接线图原理图图纸,io分配
  • 全贴合工艺中Cover Lens Mura不良的关键影响因素与优化策略
  • 【RAG】【vector_stores003】Amazon Neptune - Neptune Analytics向量存储
  • AI率超80%不要慌,这样处理比自己改快10倍
  • 从零搭建WebRTC SFU服务器:基于Mediasoup的1080P视频会议部署教程
  • 告别重复敲命令:用Claude Code + mcp-ssh-manager实现一句话服务器部署(保姆级配置)
  • claw-code 源码详细分析:子系统目录地图——几十个顶层包如何用五条轴(会话 / 工具 / 扩展 / 入口 / 桥接)读懂?
  • 利用drawio高效绘制数据库ER图:从入门到精通
  • 跳点搜索算法(JPS)融合动态窗口法,JPS规划全局路径,动态窗口法执行动态避障
  • iOS开发者证书与p12文件:从零到一的安全部署指南
  • 【SV】从仿真器调度机制看非阻塞赋值与延迟控制的协同设计。理解NBA区域与Active事件的交互
  • 物联网设备上高德地图离线地图加载慢?5秒内快速加载的终极解决方案
  • COMSOL水力压裂岩石多裂隙损伤耦合模型及含离散裂隙Matlab建模文件
  • JAVA重点基础、进阶知识及易错点总结(35)注解与反射
  • 从零实践:利用aitodpycocotools精准评估小目标检测模型的APvt/APt/APs/APm
  • 四开关Buck-Boost双向DC-DC电源系统全套学习资料:STM32F334C8T6控制下...