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

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

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

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

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

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

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

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

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

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

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

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

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

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

 装修产品类(核心配置)

class OfficeArea {
    private String areaType;    // 区域类型
    private String chairType;   // 椅子类型
    private String wifiSpec;    // WiFi配置
    private String deskStyle;   // 桌子风格
    private String specialNote; // 老板的特殊要求批注

    // 私有构造方法,禁止直接new
    private 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;
        }
    }
}

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

// 装修配置器(封装常用配置)
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();
    }
}

 实践效果

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类)
  • 运行时校验困难
    public Phone build() {
        if(ram == null) throw new Exception(); // 只能在build时校验
    }

使用场景

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

    ​终章

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

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


http://www.kler.cn/a/597650.html

相关文章:

  • MAC-在使用@Async注解的方法时,分布式锁管理和释放
  • 嵌入式开发之STM32学习笔记day08
  • Mac:Ant 下载+安装+环境配置(详细讲解)
  • Web3如何影响未来的社交平台:去中心化社交的兴起
  • 区块链在医疗数据共享中的应用:解锁安全与透明的新维度
  • 广度优先搜索(BFS) vs 深度优先搜索(DFS):算法对比与 C++ 实现
  • 洛谷 P10108 [GESP202312 六级] 闯关游戏 题解
  • Android Studio控制台中文乱码解决方案
  • Webpack vs Vite:深度对比与实战示例,如何选择最佳构建工具?
  • LeetCode热题100精讲——Top1:两数之和【哈希】
  • 如何编写一个Spring Boot Starter
  • Ubuntu YOLO5 环境安装
  • UI设计中的大数据可视化:解锁数据背后的秘密
  • 基于深度学习的图像分割项目实践:从理论到应用
  • 基于WebAssembly的浏览器密码套件
  • 【技术选型】三大 Python Web 框架全面对比
  • React学习(进阶)
  • github如何为开源项目作出贡献
  • 为什么后端路由需要携带 /api 作为前缀?前端如何设置基础路径 /api?
  • Python推导式深入解析