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

设计模式学习(7) 23-5 建造者模式

文章目录

  • 0.个人感悟
  • 建造者模式
    • 1. 概念
    • 2. 适配场景(什么场景下使用)
    • 3. 实现方法
      • 3.1 实现思路
      • 3.2 UML类图
    • 4. 代码示例
    • 5. 优缺点
    • 6. 源码分析-JDK中的StringBuilder实现分析
    • 7. vs抽象工厂模式

0.个人感悟

  • 建造者模式也是很典型的创建型设计模式。主要目的是将对象的构建和表示分离:构建角色就负责构建过程(建造者 指挥者),对象(产品)只表示自身属性
  • 建造者模式很能表现编程的一个思想:面向接口编程。我们面向对象来建模,抽取不同的角色进行分工,角色和角色之间依赖抽象,方便具体实现的替换,比如这里的具体建造者
  • 截止到目前,创建型设计模式复习完了。整体而言,目的都是创建对象,根据不同的情况来选择不同的模式,从而尽量达到1核(高内聚低耦合)4性(复用性 可读性 维护性 稳定性)7大原则(设计原则)
  • 建造者模式很容易联想到链式调用,比如常用的lombok @Builder注解,可以提高开发效率,有兴趣可以详细了解下原理和使用方法
  • 建议实际工作中多尝试使用设计模式,不怕犯错
  • 祝大家元旦快乐

建造者模式

1. 概念

英文定义(摘自《设计模式:可复用面向对象软件的基础》):

Separate the construction of a complex object from its representation so that the same construction process can create different representations.

中文翻译:

将一个复杂对象的构建与其表示分离,使得同样的构建过程可以创建不同的表示。

理解:

  • 将复杂对象的构建过程最终产品解耦

2. 适配场景(什么场景下使用)

适合的场景:

  1. 创建复杂对象: 当对象包含多个组成部分,且这些部分需要按特定顺序或规则组合时
  2. 构建过程需要精细化控制: 需要分步骤、分阶段构建对象,且构建过程可能变化
  3. 产品有多个变体: 同一个构建过程需要产生不同表示的产品
  4. 分工合作:产品的创建和产品的使用由不同的模块、责任人负责,天然契合建造者模式

常见的具体场景举例:

  • 配置对象的构建(如数据库连接配置)
  • 文档生成器(HTML、PDF等不同格式)
  • 套餐组合
  • 复杂查询构建
  • 游戏角色创建系统

3. 实现方法

3.1 实现思路

  • 分离关注点: 构建过程由指挥者(Director)控制,具体构建由建造者(Builder)实现
  • 构建与表示分离: 同样的构建步骤可以产生不同的产品表示
  • 分步构建: 允许分步骤、精细化地构建复杂对象
  • 控制反转: 客户端不直接创建对象,而是通过指挥者间接创建

3.2 UML类图

  • 产品(Product): 创建要构建的复杂对象,包含所有组成部分
  • 建造者接口(Builder): 声明创建产品各个部分的抽象方法
  • 具体建造者类(ConcreteBuilder):
    • 实现Builder接口
    • 维护当前产品的表示
    • 提供获取最终产品的方法
  • 指挥者(Director):
    • 封装构建过程
    • 使用Builder接口逐步构建产品
  • 客户端: 客户端创建具体建造者,将其传递给指挥者,然后获取最终产品

4. 代码示例

以互联网大厂夜宵文化为例:,简化一下流程,规定夜宵套餐包含 水果 饮料 主食,忽略金额

产品类

publicclassNightSnack{privateStringfruit;privateStringdrink;privateStringstapleFood;publicStringgetFruit(){returnfruit;}// 省略}

建造者类族

// 1.抽象建造者publicabstractclassSnackBuilder{NightSnacknightSnack=newNightSnack();publicabstractvoidbuildFruit();publicabstractvoidbuildDrink();publicabstractvoidbuildStapleFood();publicNightSnackgetNightSnack(){returnnightSnack;}}// 2.指挥者publicclassSnackStall{privateSnackBuildersnackBuilder;publicSnackStall(SnackBuildersnackBuilder){this.snackBuilder=snackBuilder;}publicNightSnackconstruct(){// 水果snackBuilder.buildFruit();// 饮料snackBuilder.buildDrink();// 主食snackBuilder.buildStapleFood();returnsnackBuilder.getNightSnack();}}// 3.具体建造者 套餐ApublicclassSnackAextendsSnackBuilder{@OverridepublicvoidbuildFruit(){nightSnack.setFruit("西瓜一个");}@OverridepublicvoidbuildDrink(){nightSnack.setDrink("可乐一瓶");}@OverridepublicvoidbuildStapleFood(){nightSnack.setStapleFood("螺蛳粉一碗");}}// 4.具体建造者 套餐BpublicclassSnackBextendsSnackBuilder{@OverridepublicvoidbuildFruit(){nightSnack.setFruit("酸橘子一筐");}@OverridepublicvoidbuildDrink(){nightSnack.setDrink("外星人饮品一瓶");}@OverridepublicvoidbuildStapleFood(){nightSnack.setStapleFood("面包一块");}}

客户端:

publicclassClient{staticvoidmain(){SnackBuildersnackBuilder=newSnackA();// 这里可以进行套餐更换SnackStallsnackStall=newSnackStall(snackBuilder);NightSnacknightSnack=snackStall.construct();System.out.println(STR."套餐内容: \{nightSnack.getFruit()} \{nightSnack.getDrink()} \{nightSnack.getStapleFood()}");}}

5. 优缺点

结合1核(高内聚低耦合)4性(复用性 可读性 维护性 稳定性)7大原则(设计原则):
优点:

  1. 高内聚低耦合
    • 构建过程封装在指挥者中,与具体建造者解耦
    • 产品与构建过程分离,符合单一职责原则
  2. 复用性
    • 同样的构建过程可以创建不同表示的产品
    • 指挥者代码可以复用,支持不同建造者
  3. 可读性
    • 分步骤构建,逻辑清晰
  4. 维护性
    • 新增产品变体只需添加新的建造者,无需修改现有代码
    • 符合开闭原则
  5. 稳定性
    • 可以确保产品的完整性,避免构建不完整的对象
    • 构建过程可控,减少错误

缺点:

  1. 复杂度增加
    • 需要创建多个类(Builder、Director、Product等)
    • 对于简单对象,可能显得过于复杂
  2. 性能开销
    • 相比直接创建对象,有额外的对象创建和方法调用开销。这其实是设计模式的通病,灵活性的代价
  3. 灵活性受限
    • 产品必须有共同的接口,限制了产品类型的多样性。当产品差异性很大时,不推荐使用

6. 源码分析-JDK中的StringBuilder实现分析

主要关注append方法
StringBuilder源码简化分析:

publicfinalclassStringBuilderextendsAbstractStringBuilder{// 1. 存储产品(字符串)的字符数组// char[] value; // 继承自AbstractStringBuilderpublicStringBuilder(){super(16);// 初始容量}publicStringBuilder(intcapacity){super(capacity);}publicStringBuilder(Stringstr){super(str.length()+16);append(str);// 初始内容}// 2. 建造者方法 - 添加部件@OverridepublicStringBuilderappend(Stringstr){super.append(str);returnthis;// 关键:返回this实现链式调用}@OverridepublicStringBuilderappend(charc){super.append(c);returnthis;}@OverridepublicStringBuilderappend(inti){super.append(i);returnthis;}// 3. 获取最终产品@OverridepublicStringtoString(){// 创建String对象,使用当前的字符数组returnnewString(value,0,count);}}}

AbstractStringBuilder中的append:

abstractsealedclassAbstractStringBuilderimplementsAppendable,CharSequencepermitsStringBuilder,StringBuffer{publicAbstractStringBuilderappend(Stringstr){if(str==null){returnappendNull();}intlen=str.length();ensureCapacityInternal(count+len);putStringAt(count,str);count+=len;returnthis;}}

测试:

publicclassStringTest{staticvoidmain(String[]args){// 典型的建造者模式使用方式Stringresult=newStringBuilder().append("Hello")// 构建第一部分.append(" ")// 构建第二部分.append("World")// 构建第三部分.append("!")// 构建第四部分.reverse()// 对构建结果进行操作.toString();// 获取最终产品System.out.println(result);// 输出: !dlroW olleH}}

可以看到StringBuilder中的建造者模式特点:

  1. 内聚的建造者: StringBuilder同时承担了建造者和指挥者的职责
  2. 链式调用: 每个构建方法返回this,支持流畅接口(Fluent Interface)。这个在实际工作中常用Lombok的 @Builder注解
  3. 延迟创建: 只有在调用toString()时才创建最终的String对象

7. vs抽象工厂模式

关键区别总结:

  • 建造者模式: 关注如何构建一个复杂对象,构建过程是重点。粒度更细,可以理解为车间维度
  • 抽象工厂模式: 关注创建什么产品,产品家族是重点。粒度更粗,可以理解为工厂维度

实际选择经验建议:

  • 当需要创建的对象结构复杂、构建步骤多时,使用建造者模式
  • 当需要创建一系列相关对象时,使用抽象工厂模式
  • 在某些复杂场景下,两种模式可以结合使用,一个粗粒度,一个细粒度

参考:

  • 韩顺平 Java设计模式
  • 张维鹏 Java设计模式之创建型:建造者模式)
  • 设计模式实战——开发中经常涉及到的建造者模式
http://www.jsqmd.com/news/174229/

相关文章:

  • Elasticsearch菜鸟必看:Kibana可视化环境完整部署教程
  • Let‘s Encrypt免费证书为DDColor网站启用SSL加密
  • 搭建个人博客推广DDColor项目,带动GPU资源销售
  • Java Web 校园悬赏任务平台系统源码-SpringBoot2+Vue3+MyBatis-Plus+MySQL8.0【含文档】
  • Elasticsearch检索错误信息:快速定位DDColor故障根源
  • Firecracker轻量虚拟机:为每个DDColor任务分配独立环境
  • 【中国海洋大学-蔡青组-AAAI26】SEMC:用于超声图像标准平面识别的结构增强型混合专家对比学习
  • 前后端分离校园疫情防控管理系统系统|SpringBoot+Vue+MyBatis+MySQL完整源码+部署教程
  • 开源神器DDColor上线!轻松实现老照片智能彩色化修复
  • 123云盘作为备用渠道,持续提供DDColor资源下载
  • 核心要点:USB 2.0接口定义引脚说明中的阻抗匹配要求
  • 《代码大全2》13,14,15读后感
  • 伯乐在线招聘贴植入:招AI工程师,要求熟悉DDColor等模型
  • 百度贴吧发帖引流:在摄影吧宣传DDColor修复效果
  • 模拟信号隔离技术解析:系统学习指南
  • 同或门在工业控制中的逻辑应用:深度剖析其可靠性设计
  • 为什么选择DDColor做老照片修复?技术优势深度剖析
  • 苹果App Store提交指南:将DDColor封装为iOS应用
  • 全面讲解Proteus元器件大全中的电源与地符号
  • OSCHINA技术博客撰写:提升DDColor社区影响力
  • 在婚恋中实现“先谋爱,更要谋‘靠谱’未来”的需求分析
  • GitHub镜像推荐:DDColor黑白照片修复模型快速部署教程
  • 液冷散热技术应用提升GPU能效比
  • Java Web 校园疫情防控管理系统系统源码-SpringBoot2+Vue3+MyBatis-Plus+MySQL8.0【含文档】
  • CC2530硬件设计避坑指南:新手必看的十大注意事项
  • 思否SegmentFault发文:解决DDColor部署中的典型坑点
  • 《代码大全2》16,17,18读后感
  • 校园志愿者管理系统信息管理系统源码-SpringBoot后端+Vue前端+MySQL【可直接运行】
  • 模型蒸馏技术研究压缩DDColor体积便于边缘设备部署
  • 系统学习RS485全双工通信的电气特性与距离限制