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

​约束催生自由,分离滋养创造——建造者模式有感

约束催生自由,分离滋养创造

当复杂对象如迷宫般盘踞,
它以分离为刀——剖开混沌的胎衣;
当需求如季风般无常,
它以流程为锚——锁住变幻的潮汐。
用户只见成型的殿堂,
而黑暗中的组装与呐喊,
终被驯服为静默的齿轮。

建造者模式概述

核心问题:解决复杂对象构建过程与对象表示的耦合问题,特别是当对象构建需要多个步骤、多种组合方式时的设计困境。
核心思想:将复杂对象的构建过程(建造流程)与对象的表示形式(最终产品)进行分离,使得同样的构建流程可以创建不同的产品表示。

传统方法痛点剖析

  1. 客户端过度参与:客户端直接负责对象各个部件的构建细节,如房屋建造中需要客户端依次调用建造墙体、门窗等方法。
  2. 代码脆弱性:建造流程或部件变更时,客户端代码需要大面积修改,违背开闭原则。
  3. 灵活性不足:无法便捷地切换不同的建造实现,如从建造普通住宅切换到建造别墅时需要重写大量客户端逻辑。
  4. 流程控制缺失:缺乏对构建流程的统一管理,难以保证构建步骤的正确性和一致性。

建造者模式结构

角色名称职责描述关键作用代码实现示例
Product(产品)定义要构建的复杂对象的结构和属性最终构建的目标对象House类,包含墙体、门窗等部件
Builder(抽象建造者)定义构建产品各个部件的抽象接口,规范建造流程隔离具体建造实现与产品纯虚函数接口,如buildWall()、buildRoof()
ConcreteBuilder(具体建造者)实现抽象建造者定义的接口,负责具体部件的构建提供不同的建造实现VillaBuilder(别墅建造者)、ApartmentBuilder(公寓建造者)
Director(指挥者)控制建造流程,调用建造者接口完成对象构建封装构建逻辑,隔离客户端与建造过程Architect类,定义construct()方法

角色协作流程图

在这里插入图片描述

建造者模式优势与应用价值

  1. 解耦与分离
    • 构建流程与产品表示分离,使代码结构更清晰
    • 客户端与具体建造逻辑分离,降低系统耦合度
  2. 灵活性与扩展性
    • 新增具体建造者无需修改现有代码,符合开闭原则
    • 同一构建流程可生成不同产品,满足多样化需求
  3. 流程控制与一致性
    • 指挥者统一管理构建流程,确保步骤正确性
    • 避免客户端直接操作导致的构建顺序错误
  4. 复用性与可维护性
    • 建造者逻辑可复用,减少代码重复
    • 单一职责原则的体现,便于维护和扩展

与其他创建型模式的对比

模式名称核心区别适用场景
建造者模式关注复杂对象的分步构建与流程控制对象构建需要多步骤、多部件组合
工厂方法模式关注对象的创建接口与实现分离需动态决定创建对象的具体类型
抽象工厂模式关注相关对象家族的创建需创建一系列相关或依赖的对象

代码实现与运行演示

类结构与头文件设计

// House.h - 产品类定义
#ifndef HOUSE_H
#define HOUSE_H#include <string>
#include <iostream>class House {
private:std::string wallMaterial;   // 墙体材料std::string doorType;       // 门的类型std::string windowType;     // 窗的类型std::string roofStyle;      // 屋顶样式public:void setWallMaterial(const std::string& material) {wallMaterial = material;}void setDoorType(const std::string& type) {doorType = type;}void setWindowType(const std::string& type) {windowType = type;}void setRoofStyle(const std::string& style) {roofStyle = style;}// 显示房屋信息void showHouse() const {std::cout << "===== 房屋信息 =====" << std::endl;std::cout << "墙体材料: " << wallMaterial << std::endl;std::cout << "门的类型: " << doorType << std::endl;std::cout << "窗的类型: " << windowType << std::endl;std::cout << "屋顶样式: " << roofStyle << std::endl;}
};#endif // HOUSE_H
// IBuilder.h - 抽象建造者接口
#ifndef IBULDER_H
#define IBULDER_H#include "House.h"class IBuilder {
public:virtual ~IBuilder() = default;// 定义建造各个部件的接口virtual void buildWall() = 0;virtual void buildDoor() = 0;virtual void buildWindow() = 0;virtual void buildRoof() = 0;// 获取建造结果virtual House* getHouse() = 0;
};#endif // IBULDER_H
// VillaBuilder.h - 别墅建造者
#ifndef VILLABUILDER_H
#define VILLABUILDER_H#include "IBuilder.h"class VillaBuilder : public IBuilder {
private:House* villa;public:VillaBuilder() {villa = new House();}~VillaBuilder() {if (villa) {delete villa;villa = nullptr;}}void buildWall() override {villa->setWallMaterial("大理石");}void buildDoor() override {villa->setDoorType("实木雕花大门");}void buildWindow() override {villa->setWindowType("断桥铝落地窗");}void buildRoof() override {villa->setRoofStyle("斜坡式红瓦屋顶");}House* getHouse() override {return villa;}
};#endif // VILLABUILDER_H
// ApartmentBuilder.h - 公寓建造者
#ifndef APARTMENTBUILDER_H
#define APARTMENTBUILDER_H#include "IBuilder.h"class ApartmentBuilder : public IBuilder {
private:House* apartment;public:ApartmentBuilder() {apartment = new House();}~ApartmentBuilder() {if (apartment) {delete apartment;apartment = nullptr;}}void buildWall() override {apartment->setWallMaterial("钢筋混凝土");}void buildDoor() override {apartment->setDoorType("防盗门");}void buildWindow() override {apartment->setWindowType("双层玻璃平开窗");}void buildRoof() override {apartment->setRoofStyle("平顶式防水屋顶");}House* getHouse() override {return apartment;}
};#endif // APARTMENTBUILDER_H
// Architect.h - 指挥者类
#ifndef ARCHITECT_H
#define ARCHITECT_H#include "IBuilder.h"class Architect {
private:IBuilder* builder;public:Architect(IBuilder* b) : builder(b) {}// 定义标准建造流程void construct() {builder->buildWall();builder->buildRoof();builder->buildWindow();builder->buildDoor();}// 定义快速建造流程(简化版)void quickConstruct() {builder->buildWall();builder->buildDoor();builder->buildWindow();}
};#endif // ARCHITECT_H

客户端调用与运行演示

// main.cpp - 客户端代码
#include <iostream>
#include "Architect.h"
#include "VillaBuilder.h"
#include "ApartmentBuilder.h"int main() {std::cout << "===== 建造者模式演示 =====" << std::endl;// 场景1:建造别墅std::cout << "\n--- 开始建造别墅 ---" << std::endl;IBuilder* villaBuilder = new VillaBuilder();Architect* architect = new Architect(villaBuilder);// 使用标准建造流程architect->construct();// 获取建造好的别墅House* villa = villaBuilder->getHouse();if (villa) {villa->showHouse();}// 清理资源delete architect;delete villaBuilder;// 场景2:建造公寓std::cout << "\n--- 开始建造公寓 ---" << std::endl;IBuilder* apartmentBuilder = new ApartmentBuilder();architect = new Architect(apartmentBuilder);// 使用快速建造流程architect->quickConstruct();// 获取建造好的公寓House* apartment = apartmentBuilder->getHouse();if (apartment) {apartment->showHouse();}// 清理资源delete architect;delete apartmentBuilder;std::cout << "\n--- 演示结束 ---" << std::endl;return 0;
}

代码运行结果

===== 建造者模式演示 =====--- 开始建造别墅 ---
===== 房屋信息 =====
墙体材料: 大理石
门的类型: 实木雕花大门
窗的类型: 断桥铝落地窗
屋顶样式: 斜坡式红瓦屋顶--- 开始建造公寓 ---
===== 房屋信息 =====
墙体材料: 钢筋混凝土
门的类型: 防盗门
窗的类型: 双层玻璃平开窗
屋顶样式: 平顶式防水屋顶--- 演示结束 ---

应用场景

  1. 复杂对象构建
    • 文档处理系统:构建包含文字、图片、表格的复杂文档
    • 游戏场景生成:构建包含地形、建筑、NPC的游戏场景
    • 报表生成器:构建包含数据图表、文字说明的复杂报表
  2. 产品配置与定制
    • 汽车配置系统:不同配置(引擎、内饰、外观)的汽车构建
    • 家具定制系统:不同材质、尺寸、风格的家具构建
    • 软件安装程序:根据用户选择安装不同组件的软件
  3. 流程化处理
    • 数据处理流程:数据采集、清洗、转换、存储的流程化处理
    • 订单处理系统:订单验证、支付处理、库存更新、物流安排的流程控制

常见问题

Q1:建造者模式与抽象工厂模式的区别是什么?
A1:

  • 抽象工厂模式关注的是相关对象家族的创建,返回的是多个相关对象的集合
  • 建造者模式关注的是复杂对象的分步构建,返回的是一个完整的复杂对象
  • 简单来说:抽象工厂生产"产品家族",建造者生产"复杂产品"

Q2:什么时候需要使用指挥者角色?
A2:

  • 当构建流程比较固定且需要统一管理时,建议使用指挥者
  • 当构建流程需要灵活变化时,可以省略指挥者,由客户端直接调用建造者
  • 指挥者的存在不是必须的,可根据实际需求决定是否引入

Q3:如何处理建造过程中的可选部件?
A3:

  • 在抽象建造者中定义可选部件的构建方法,具体建造者可选择性实现
  • 使用建造者模式的变种,如链式建造者(Fluent Builder),支持方法链调用
  • 示例:houseBuilder.buildWall().buildDoor().buildWindowIfNeeded().buildRoof();

常见陷阱与解决方案

  1. 过度设计问题
    • 陷阱:将简单对象的构建也使用建造者模式,增加系统复杂度
    • 解决方案:仅在对象构建复杂、步骤多的情况下使用建造者模式
  2. 建造者泄漏问题
    • 陷阱:建造者中保存了过多的状态信息,导致内存泄漏
    • 解决方案:实现建造者的资源管理机制,如使用智能指针、析构函数清理
  3. 流程控制混乱
    • 陷阱:构建流程缺乏统一管理,导致对象构建不完整
    • 解决方案:合理使用指挥者角色,规范构建流程,必要时添加流程验证

模式扩展

链式建造者(Fluent Builder)

核心思想:使建造者的方法返回自身引用,支持方法链调用,提高代码可读性和易用性。

代码示例

class FluentHouseBuilder {
private:House* house;public:FluentHouseBuilder() {house = new House();}~FluentHouseBuilder() {if (house) {delete house;house = nullptr;}}FluentHouseBuilder& buildWall(const std::string& material) {house->setWallMaterial(material);return *this;}FluentHouseBuilder& buildDoor(const std::string& type) {house->setDoorType(type);return *this;}FluentHouseBuilder& buildWindow(const std::string& type) {house->setWindowType(type);return *this;}FluentHouseBuilder& buildRoof(const std::string& style) {house->setRoofStyle(style);return *this;}House* getHouse() {return house;}
};// 客户端调用
FluentHouseBuilder builder;
House* specialHouse = builder.buildWall("青砖").buildDoor("古典木门").buildWindow("仿古木窗").getHouse();

多产品建造者

核心思想:允许一个建造者构建多种不同但相关的产品。

实现要点

  • 在抽象建造者中定义多个产品的构建方法
  • 具体建造者实现这些方法,构建不同的产品
  • 指挥者根据需要调用相应的构建方法

参考

[1] 大话设计模式
[2] C++进阶-UML与设计模式

http://www.xdnf.cn/news/13803.html

相关文章:

  • /proc/<pid>/maps文件格式详解
  • Git 常用总结
  • Unity | AmplifyShaderEditor插件基础(第十集:shader的基本属性+火焰制作-上)
  • 使用cmake安装faiss-GPU.so(无网或者内网情况下)
  • 《网络安全与防护》知识点复习
  • 多通道信号采集分析系统 - 01 功能分解与采样子系统
  • 体育赛事直播平台需要有哪些数据?
  • 通用人工智能离我们还有多远?从认知模型到大模型的深度解析
  • JavaScript中声明变量的关键字const/let/var区别
  • 13-Linux启动流程和内核管理自我总结
  • python根据图片路径获取文件后缀名
  • Spring Boot Actuator 健康信息
  • OpenLayers 动画
  • 零基础RT-thread第一节:串口通信UART
  • C语言——指针
  • 实现AI数据高效评估的一种方法
  • 分水岭边缘提取和hough提取边缘
  • ubuntu20上 : mujoco210安装教程
  • 计算机系统设计:E-R图、类图、时序图、功能结构图、流程图、用例图、架构图
  • 【ARMv7-A】——CLZ 指令
  • 【25-cv-06400、25-cv-06413】Keith律所再次代理Elizabeth Anne Evans蝴蝶版权画
  • 使用MetaGPT 创建智能体(3)常用操作和晋级
  • < 自用文儿 腾讯云 VPS > Ubuntu 24 系统,基本设置
  • 无人机接收机运行技术要点分析!
  • 基于SC内存一致性模型两个核心约束的放松维度
  • Systemctl 手记:从服务管理到资源控制的进阶实践
  • AI时代,学习力进化指南:如何成为知识的主人?
  • JSON 与 AJAX
  • 开疆智能ModbusTCP转Devicenet网关连接ABB机器人配置案例
  • 网页中调用自定义字体可以通过 ‌CSS‌ 的 @font-face 规则实现