周五的早上,项目经理小白还沉浸在即将到达的假期的喜悦中,喝着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
和重复代码,小白突然发现:
- 每次新增区域都要修改核心类,迟早变成"屎山代码"
- 客户接待室的判断条件居然写错成BOSS_ROOM(复制粘贴惹的祸)
- 智能桌子的配置参数和普通桌子完全混在一起
这样子可不行呀,如果后续再增加一个临时办公室,又得一堆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();
终章
当小白提交完最后一行代码,窗外已是凌晨三点的月光。他望着屏幕上优雅的建造者配置链,突然领悟到一个真理:
**"这世上本没有需求黑洞,老板的脑洞大了,便成了黑洞。"**