java设计模式之建造者模式《装修启示录》​

server/2025/4/1 15:47:22/
周五的早上,项目经理小白还沉浸在即将到达的假期的喜悦中,喝着9块9的瑞幸咖啡畅想人生时,老板突然拍出一张装修设计图:"小~白~啊(此处请脑补领导拉长音),新办公室装修就交给你了!年轻人要多锻炼!公司不提倡加班,周一早上弄好给我就行" 话没说完,老板都走远了。
小白连忙放下手中的咖啡,揣着设计图看了起来,原来新办公室要分成三个区域。
  • 开放办公区:要体现"互联网狼性文化"(翻译:桌子挤到放不下水杯)
  • 高管会议室:必须彰显"行业领军地位"(翻译:椅子要比老板现在的再贵2000)
  • 茶水间:得营造"家一般的温暖"(翻译:预算砍半但效果要媲美星巴克)

这时候,小白脑中已经构想出来了实施方案:

java">// 装修团队  
class DecorationTeam {// areaType 装修的区域public void decorate(String areaType) {//  开放办公区if ("OPEN_OFFICE".equals(areaType)) {buyChairs();      // 批发椅子installCheapWifi(); // 装最便宜的WiFicrampDesks();       // 把桌子塞成沙丁鱼罐头// 高管会议室or 老板 会议室} else if ("BOSS_ROOM".equals(areaType)) {importItalianChair(); // 进口意大利真皮椅topWifi(); // 企业级万兆WiFichenxiangmuDesks(); //沉香木桌子addFakeArt();       // 挂淘宝99包邮的抽象画}}
}

经过一早上的努力,实施方案已经出来了,小白翘着二郎腿,又开始美滋滋幻想放假的日子了。但是,下午行政小妹又来传达BOOS的意思,要再划分个客户接待室。临时该需求,这一幕可太熟悉了,一顿哐哐下来,施工图又改好了。

java">// 装修团队  
class DecorationTeam {// areaType 装修的区域public void decorate(String areaType) {//  开放办公区if ("OPEN_OFFICE".equals(areaType)) {buyChairs();      // 批发椅子installCheapWifi(); // 装最便宜的WiFicrampDesks();       // 把桌子塞成沙丁鱼罐头// 高管会议室or 老板 会议室} else if ("BOSS_ROOM".equals(areaType)) {importItalianChair(); // 进口意大利真皮椅topWifi(); // 企业级万兆WiFichenxiangmuDesks(); //沉香木桌子addFakeArt();       // 挂淘宝99包邮的抽象画// 客户接待室} else if ("CUSTOMER_ROOM".equals(areaType)) {normalChairs(); // 普通座椅100mwifi(); // 100兆wifiofficeDesks(); //办公型桌子}}
}

但是小白这次并没有松懈,因为有句老话说得好:改需求只有第一次跟无数次
果然,临近下班的时候,微信传来了老板的信息:小白,最近的AI那么火,再加个AI创意室吧,很快的,改改就好了。
已经红温的小白经过1秒的内心平复后:好的,老板。
进过一晚上的加班,新一版的施工图纸又出来了。

java">// 装修团队  
class DecorationTeam {// areaType 装修的区域public void decorate(String areaType) {//  开放办公区if ("OPEN_OFFICE".equals(areaType)) {buyChairs();      // 批发椅子installCheapWifi(); // 装最便宜的WiFicrampDesks();       // 把桌子塞成沙丁鱼罐头// 高管会议室or 老板 会议室} else if ("BOSS_ROOM".equals(areaType)) {importItalianChair(); // 进口意大利真皮椅topWifi(); // 企业级万兆WiFichenxiangmuDesks(); //沉香木桌子addFakeArt();       // 挂淘宝99包邮的抽象画// 客户接待室} else if ("BOSS_ROOM".equals(areaType)) {normalChairs(); // 普通座椅100mwifi(); // 100兆wifiofficeDesks(); //办公型桌子// AI创意室	}else if ("AI_ROMM".equals(areaType)) {smartChairs(); // 智能椅子smartWifi(); // 智能WIFIsmartDesks();  // 智能桌子}}
}

 小白揣着施工图看了一会,看着满屏重复的if-else和重复代码,小白突然发现:

  1. 每次新增区域都要修改核心类,迟早变成"屎山代码"
  2. 客户接待室的判断条件居然写错成BOSS_ROOM​(复制粘贴惹的祸)
  3. 智能桌子的配置参数和普通桌子完全混在一起
     

这样子可不行呀,如果后续再增加一个临时办公室,又得一堆if  else , 虽然现在流行防御性编程,但是也得看是谁维护啊,自己维护还防御个啥。。。。小白在苦思冥想解决方案时,发现被压在桌底的一本书,隐隐约约露出<设计模式>四个字,小白把它抽了出来,拍了拍灰尘,还好,没被老鼠咬坏。打开书,扫下了所有的设计模式,结合当前的业务
(所有房间所需要的  椅子类型、WiFi配置、桌子风格 都是固定的)那使用建造者模式不就好了。说干就干。干之前先回顾下

什么是建造者模式?
把一个复杂对象的构建过程拆解成多个步骤,通过链式调用逐步组装参数,最终像搭积木一样创建出灵活配置的对象。

核心三要素
   产品(Product)​:最终要创建的复杂对象(如装修方案、电脑配置)
   ​建造者(Builder)​:定义组件的接口 + 实现具体构建步骤(如.setChair()、.setWifi())
  指挥者(Director)​:可选 封装常用配置模板(如一键生成"狼性文化工位"模板)
  
理解了该设计模式后,小白信心十足,就着手开始修改。

 装修产品类(核心配置)

java">class OfficeArea {private String areaType;    // 区域类型private String chairType;   // 椅子类型private String wifiSpec;    // WiFi配置private String deskStyle;   // 桌子风格private String specialNote; // 老板的特殊要求批注// 私有构造方法,禁止直接newprivate OfficeArea() {}// 显示装修方案public void showPlan() {System.out.println("\n=== " + areaType + "装修方案 ===");System.out.println("椅子类型:" + chairType);System.out.println("WiFi配置:" + wifiSpec);System.out.println("桌子风格:" + deskStyle);if(specialNote != null) {System.out.println("老板批注:" + specialNote);}}// 建造者(核心)static class Builder {private OfficeArea area = new OfficeArea();// 必须指定区域类型public Builder(String type) {area.areaType = type;}// 配置方法链(老板的每个要求对应一个方法)public Builder setChair(String type) {area.chairType = type;return this;}public Builder setWifi(String spec) {area.wifiSpec = spec;return this;}public Builder setDesk(String style) {area.deskStyle = style;return this;}public Builder bossSaid(String note) {area.specialNote = note;return this;}// 最终构建方法public OfficeArea build() {// 自动补全老板的经典语录if(area.specialNote == null) {area.specialNote = "要大气!要省钱!"; }return area;}}
}

装修配置器(封装常用配置) 

java">// 装修配置器(封装常用配置)
class AreaPreset {// 狼性文化办公区(桌子挤到放不下水杯)public static OfficeArea wolfCulture() {return new OfficeArea.Builder("开放办公区").setChair("批发塑料椅").setWifi("最低配路由器").setDesk("间距<30cm的密集排列").bossSaid("体现团队拼搏精神").build();}// 土豪老板会议室(椅子比现在贵2000)public static OfficeArea bossRoom() {return new OfficeArea.Builder("高管会议室").setChair("意大利进口真皮椅(+2000升级款)").setWifi("万兆企业级WiFi").setDesk("沉香木会议桌").bossSaid("我的椅子要比王总的贵").build();}
}

 实践效果

java">public class BuilderDemo {public static void main(String[] args) {// 原有需求快速配置OfficeArea openArea = AreaPreset.wolfCulture();openArea.showPlan();// 突然新增的客户接待室需求(临时配置)OfficeArea clientLounge = new OfficeArea.Builder("客户接待室").setChair("宜家简约款").setWifi("百兆商用网络").setDesk("弧形协作桌").bossSaid("看起来要比竞品公司高端").build();clientLounge.showPlan();// 老板临时加的AI创意室(配置灵活扩展)OfficeArea aiRoom = new OfficeArea.Builder("AI创意室").setChair("电竞人体工学椅").setWifi("WiFi6+蓝牙Mesh").setDesk("智能升降桌").bossSaid("要能拍抖音的那种科技感").build();aiRoom.showPlan();}
}

优势分析 

  • 新增区域类型时只需新建Builder配置,无需碰核心类代码
     
  • 各区域的配置参数完全隔离,不会出现误修改
  • 支持临时魔改配置(比如给茶水间加个电竞椅)
  • 可以复用现有配置(如AreaPreset中的预设方案)

劣势分析

  • 代码复杂度增加(每个产品类都需要配套Builder类)
  • 对象属性变更成本高(产品类的属性变化需要同步修改Builder类)
  • 运行时校验困难
    java">public Phone build() {if(ram == null) throw new Exception(); // 只能在build时校验
    }

使用场景

  • 参数多且存在组合需求
    java">// 电商商品SKU系统
    new SkuBuilder().id("GX-2038").color("星空灰").size("XL").material("纯棉").batch("2023A").build();
  • 需要分步构造复杂对象
    java">// 构建游戏角色
    Character hero = new CharacterBuilder().setBaseInfo("勇者", 1).equipWeapon("圣剑").learnSkill("旋风斩").mountPet("黄金狮鹫").build();
  • 要求对象不可变
    java">// 线程安全的配置对象
    class AppConfig {private final String dbUrl;private final int threadPoolSize;// 只能通过Builder设置final字段private AppConfig(Builder builder) { /*...*/ }
    }
  • 需要多种对象变体
    java">// 快餐套餐组合
    Meal kidsMeal = Meal.builder() // 儿童套餐.main("小汉堡").drink("牛奶").toy("卡通玩偶").build();Meal businessMeal = Meal.builder() // 商务套餐.main("牛排").drink("红酒").discountCoupon().build();

    ​终章

    当小白提交完最后一行代码,窗外已是凌晨三点的月光。他望着屏幕上优雅的建造者配置链,突然领悟到一个真理:

    ​**"这世上本没有需求黑洞,老板的脑洞大了,便成了黑洞。"**

文章来源:https://blog.csdn.net/huang_xiaoen/article/details/146377618
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.ppmy.cn/server/178544.html

相关文章

[GHCTF 2025]Popppppp[pop链构造] [php原生类的利用] [双md5加密绕过]

题目 <?php error_reporting(0);class CherryBlossom {public $fruit1;public $fruit2;public function __construct($a) {$this->fruit1 $a;}function __destruct() {echo $this->fruit1;}public function __toString() {$newFunc $this->fruit2;return $new…

使用hel-micro微服务实现在jsp项目中引入react组件

以下是一个完整的示例&#xff0c;涵盖 React子应用配置、JSP主应用集成 以及 样式隔离 的实现细节。我们将通过 CSS Modules 和 Shadow DOM 确保React样式与JSP样式互不干扰。 一、React子应用配置 1. 项目结构 react-module/ ├── src/ │ ├── index.js # 模块…

LeetCode面试经典150题

目录 力扣80. 删除有序数组中的重复项 II 代码解析 力扣274. H 指数 代码解析 力扣151. 反转字符串中的单词 解析代码 力扣12. 整数转罗马数字 解析代码 力扣28. 找出字符串中第一个匹配项的下标 解析代码1&#xff08;暴力模拟&#xff09; 解析代码2&#xff08;K…

JVM的组成--运行时数据区

JVM的组成 1、类加载器&#xff08;ClassLoader&#xff09; 类加载器负责将字节码文件从文件系统中加载到JVM中&#xff0c;分为&#xff1a;加载、链接&#xff08;验证、准备、解析&#xff09;、和初始化三个阶段 2、运行时数据区 运行时数据区包括&#xff1a;程序计数…

golang单机锁实现

1、锁的概念引入 首先&#xff0c;为什么需要锁&#xff1f; 在并发编程中&#xff0c;多个线程或进程可能同时访问和修改同一个共享资源&#xff08;例如变量、数据结构、文件&#xff09;等&#xff0c;若不引入合适的同步机制&#xff0c;会引发以下问题&#xff1a; 数据竞…

国产AI编程工具,助力3D“微”引擎开发!——从一场直播到工业科技需求的革新实践

开篇&#xff1a;一场直播引发的3D”微“引擎开发热潮 前几天&#xff0c;红孩儿在其《Python小白玩转3D引擎开发》直播中&#xff0c;邀请到了工业软件企业苏州中源广科信息科技有限公司董事长 张麟 博士 给大家分享在工业企业中&#xff0c;3D“微”引擎开发的巨大价值。 张…

基于YOLOv8深度学习的智能小麦害虫检测识别系统

作者简介&#xff1a;Java领域优质创作者、CSDN博客专家 、CSDN内容合伙人、掘金特邀作者、阿里云博客专家、51CTO特邀作者、多年架构师设计经验、多年校企合作经验&#xff0c;被多个学校常年聘为校外企业导师&#xff0c;指导学生毕业设计并参与学生毕业答辩指导&#xff0c;…

flutter本地运行web端图片跨域解决

方法一&#xff1a;只适用开发阶段 修改Flutter SDK中的chrome.dart文件&#xff0c;添加--disable-web-security参数以关闭浏览器的跨域限制。 步骤&#xff1a; 找到路径&#xff1a;Flutter/packages/flutter_tools/lib/src/web/chrome.dart 在--enable-experimental-web-…