从装饰者到桥接再到工厂:模式组合的艺术

前言:为什么要学模式组合?

学单个设计模式就像学武术招式,模式组合才是真正的实战!很多面试官喜欢问:"这几个模式有什么区别?能一起用吗?"------因为他们想知道你是否真的懂设计模式,而不是只会背定义。


第一章:装饰者模式 - "俄罗斯套娃"的艺术

1.1 生活中的装饰者

想象你去星巴克点咖啡:

  • 基础:拿铁咖啡(20元)

  • 加糖:+2元

  • 加奶:+5元

  • 加奶油:+8元

如果用传统继承,你会需要:

java 复制代码
class Latte {}                    // 拿铁
class LatteWithSugar {}           // 拿铁加糖
class LatteWithMilk {}            // 拿铁加奶
class LatteWithSugarAndMilk {}    // 拿铁加糖加奶
// ... 类爆炸!

1.2 装饰者模式的拯救

装饰者模式说:"别急,我们来玩俄罗斯套娃!"

java 复制代码
// 核心咖啡
Coffee coffee = new Latte();

// 加糖(套一层)
coffee = new Sugar(coffee);

// 加奶(再套一层)  
coffee = new Milk(coffee);

// 加奶油(再套一层)
coffee = new Cream(coffee);

System.out.println("总价:" + coffee.cost());  // 20+2+5+8=35元

1.3 装饰者的核心魔法

java 复制代码
// 魔法代码:既是Component,又有Component
abstract class CoffeeDecorator implements Coffee {  // 我是咖啡
    protected Coffee coffee;                       // 我也有咖啡
    
    public CoffeeDecorator(Coffee coffee) {
        this.coffee = coffee;  // 套娃开始了!
    }
}

关键理解:装饰者就像套娃,每个娃娃外表看起来都一样,但大娃娃里面套着小娃娃。


第二章:桥接模式 - "婚姻介绍所"的智慧

2.1 当装饰者遇到麻烦

假设咖啡不仅有配料,还有不同杯型:

  • 小杯、中杯、大杯

  • 热饮、冰饮

如果用装饰者处理所有维度:

java 复制代码
// 越来越复杂...
Coffee coffee = new Large(
                new Iced(
                new Sugar(
                new Milk(new Latte()))));
// 这代码看起来像什么?

2.2 桥接模式的哲学

桥接模式说:"别把所有东西都套在一起!有些维度应该平等相处。"

比如图形系统

  • 维度1:形状(圆形、方形)

  • 维度2:颜色(红色、蓝色)

传统继承需要:红圆、蓝圆、红方、蓝方 → 4个类

桥接模式:形状类 + 颜色类 → 2+2=4个类(但更灵活)

2.3 桥接模式的代码之美

java 复制代码
// 形状和颜色是平等的"合伙人"
abstract class Shape {
    protected Color color;  // 桥接的关键!
    
    public Shape(Color color) {
        this.color = color;  // 形状"持有"颜色
    }
}

class Circle extends Shape {
    public void draw() {
        System.out.print("圆形");
        color.applyColor();  // 让颜色来上色
    }
}

// 使用
Shape redCircle = new Circle(new Red());
redCircle.draw();  // 输出:圆形[红色]

关键理解:桥接模式让两个维度"门当户对、平等合作",而不是一个依附另一个。


第三章:装饰者 vs 桥接

3.1 快速区分口诀

java 复制代码
装饰者模式:A ← B ← C  (B和C装饰A)
           咖啡 ← 糖 ← 奶
           "纵向套娃"

桥接模式:A × B  (A和B平等)
         形状 × 颜色  
         "横向合作"

3.2 经典对比表

方面 装饰者模式 桥接模式
关系 主从关系(装饰者依附被装饰者) 平等关系
变化 纵向叠加功能 横向分离维度
比喻 穿衣打扮(内衣+衬衫+外套) 婚姻介绍(男方×女方)
代码 new A(new B(new C())) new A(new B())

3.3 实战选择题

场景:设计一个游戏角色系统,有职业(战士、法师)和装备(剑、法杖)

应该用哪个模式?

  • 装饰者? 装备不是"装饰"职业,装备可以独立存在

  • 桥接? 职业和装备是两个平等维度


第四章:抽象工厂 - "家族企业"的传承

4.1 当维度太多怎么办?

假设我们不仅有:

  • 咖啡类型(拿铁、美式)

  • 杯型(大、中、小)

  • 配料(糖、奶)

还要支持不同品牌:

  • 星巴克:默认加糖

  • 瑞幸:默认加奶

  • COSTA:默认加奶油

4.2 抽象工厂登场

抽象工厂说:"我来负责创建一整套产品!"

java 复制代码
// 抽象工厂:定义咖啡店的"产品线"
interface CoffeeShopFactory {
    Coffee createCoffee();      // 咖啡
    Dessert createDessert();    // 甜点
    Cup createCup();           // 杯子
}

// 星巴克工厂
class StarbucksFactory implements CoffeeShopFactory {
    public Coffee createCoffee() {
        Coffee coffee = new Latte(new LargeCup());  // 桥接
        coffee = new Sugar(coffee);                 // 装饰者
        return coffee;  // 星巴克默认大杯拿铁加糖
    }
}

4.3 三种模式的分工

java 复制代码
抽象工厂:老板(决定用什么"品牌套餐")
桥接模式:建筑师(设计"户型结构")  
装饰者模式:装修工(添加"软装配饰")

第五章:终极组合

5.1 现实案例:豪华咖啡系统

java 复制代码
public class UltimateCoffeeSystem {
    public static void main(String[] args) {
        // 1. 抽象工厂:选择品牌
        CoffeeShopFactory factory = new StarbucksFactory();
        
        // 2. 创建基础咖啡(工厂内部用桥接)
        Coffee coffee = factory.createCoffee();
        // 此时得到:大杯拿铁(桥接结果)+ 糖(装饰者)
        
        // 3. 用户个性化定制(额外装饰)
        if (userWantsMilk) {
            coffee = new Milk(coffee);  // 再加奶
        }
        
        // 最终:大杯拿铁 + 糖 + 奶
        System.out.println("您的订单:" + coffee.getDesc());
        System.out.println("总价:¥" + coffee.cost());
    }
}

5.2 组合模式的威力

假设我们要支持:

  • 3个品牌(星巴克、瑞幸、COSTA)

  • 4种咖啡(拿铁、美式、卡布、摩卡)

  • 3种杯型(大、中、小)

  • 5种配料(糖、奶、奶油、焦糖、肉桂)

传统继承需要 :3 × 4 × 3 × 2^5 = 1152 个类!
模式组合只需:3 + 4 + 3 + 5 = 15 个类!

5.3 什么时候用这个"豪华套餐"?

java 复制代码
// 适合用:
if (系统复杂 && 需求多变 && 需要灵活扩展) {
    使用模式组合();
}

// 不适合用:  
if (需求简单 || 时间紧张 || 团队经验不足) {
    用最简单的方式实现();
}

第六章:警告!不要盲目追求模式

6.1 什么时候该用简单设计?

java 复制代码
// 场景:公司内部工具,就5个人用
// 简单方案:
class 简单咖啡 {
    private String 类型;
    private String 杯型;
    private List<String> 配料;
    
    public double 计算价格() {
        // 简单逻辑直接写
        double 价格 = 基础价格[类型] * 杯型系数[杯型];
        for (String 料 : 配料) {
            价格 += 配料价格[料];
        }
        return 价格;
    }
}
// 简单、直接、好维护

6.2 设计模式使用原则

原则1:从简单开始

复制代码
// 第一版:直接实现
// 第二版:发现需要加配料 → 引入装饰者
// 第三版:发现多品牌 → 引入工厂
// 第四版:发现规格复杂 → 引入桥接
// 不要第一版就上全套!

原则2:为变化而设计,不为可能性

复制代码
// 错误的:“万一以后要支持100种配料呢?”
// 正确的:“目前有3种配料,用简单方案,等真有10种时再重构”

原则3:团队能力很重要

复制代码
// 如果团队都不懂设计模式:
// 用复杂模式 = 维护灾难
// 用简单方案 = 大家都能改

总结:设计模式的真正价值

学设计模式不是为了炫技,而是为了:

  1. 写出更灵活的代码(明天需求变了,我改得少)

  2. 写出更易维护的代码(同事能看懂,能接手)

  3. 写出更优雅的代码(自己看着舒服)

记住

  • 模式是工具,不是目的

  • 简单够用就好,不要过度设计

  • 理解思想比记住结构更重要

相关推荐
say_fall31 分钟前
C语言编程实战:每日一题:随机链表的复制
c语言·开发语言·链表
海中有金31 分钟前
设计模式[2]——抽象工厂模式一分钟说清
设计模式·抽象工厂模式
饕餮争锋32 分钟前
Spring内置的Bean作用域介绍
java·后端·spring
却话巴山夜雨时i32 分钟前
394. 字符串解码【中等】
java·数据结构·算法·leetcode
拾贰_C39 分钟前
【Python | Anaconda】 python-Anaconda 一些命令使用
开发语言·python
张人大 Renda Zhang1 小时前
Java 虚拟线程 Virtual Thread:让“每请求一线程”在高并发时代复活
java·jvm·后端·spring·架构·web·虚拟线程
一勺菠萝丶1 小时前
解决 SLF4J 警告问题 - 完整指南
java·spring boot·后端
济南壹软网络科技有限公司1 小时前
架构深潜:通霸IM——私有化部署、全链路开源的高可用企业级即时通讯技术基座
java·架构·开源·即时通讯源码·即时通讯im
二川bro1 小时前
循环性能提升:Python向量化计算技巧
开发语言·python