23种设计模式之装饰器模式

以下是 装饰器模式 (Decorator Pattern) 的详细介绍,包含定义、优缺点、应用场景及代码实现:


一、装饰器模式概述

  • 英文名称:Decorator

  • 核心目标动态地为对象添加额外的职责,且不改变其原有结构,提供比继承更灵活的扩展方式。

  • 设计思想:通过包装对象(即装饰器)增强功能,形成链式调用结构,支持功能的组合叠加。


二、优缺点

优点
  1. 灵活扩展:运行时动态添加或撤销功能,避免继承导致的类爆炸。

  2. 符合开闭原则:新增装饰器无需修改原有代码。

  3. 组合优于继承:通过多层装饰实现复杂功能叠加。

缺点
  1. 代码复杂度增加:需管理多个装饰器类及调用顺序。

  2. 调试困难:多层装饰可能使调试链路变长。


三、应用场景

  1. Java I/O 流:如 BufferedInputStream 包装 FileInputStream

  2. GUI 组件:动态为按钮、窗口添加边框、滚动条等。

  3. 中间件增强:为 HTTP 请求添加日志、缓存、鉴权等处理层。

  4. 游戏角色装备:动态叠加武器、护甲等装备效果。


四、代码实现与注释

以下通过 咖啡订单系统 的案例演示装饰器模式:


1. 抽象组件(咖啡接口)

/**
 * 抽象组件:定义咖啡的基本接口
 */
public interface Coffee {
    // 获取咖啡描述
    String getDescription();
    
    // 计算价格
    double getCost();
}

2. 具体组件(基础咖啡类型)

/**
 * 具体组件:浓缩咖啡(基础咖啡)
 */
public class Espresso implements Coffee {
    @Override
    public String getDescription() {
        return "浓缩咖啡";
    }

    @Override
    public double getCost() {
        return 2.0;  // 基础价格 2 元
    }
}

/**
 * 具体组件:深焙咖啡(基础咖啡)
 */
public class DarkRoast implements Coffee {
    @Override
    public String getDescription() {
        return "深焙咖啡";
    }

    @Override
    public double getCost() {
        return 2.5;
    }
}

3. 抽象装饰器(调料基类)

/**
 * 抽象装饰器:持有咖啡对象的引用,并实现 Coffee 接口
 */
public abstract class CoffeeDecorator implements Coffee {
    protected Coffee decoratedCoffee;

    public CoffeeDecorator(Coffee coffee) {
        this.decoratedCoffee = coffee;
    }

    // 默认调用被装饰对象的方法
    @Override
    public String getDescription() {
        return decoratedCoffee.getDescription();
    }

    @Override
    public double getCost() {
        return decoratedCoffee.getCost();
    }
}

4. 具体装饰器(调料实现)

/**
 * 具体装饰器:牛奶(添加牛奶调料)
 */
public class Milk extends CoffeeDecorator {
    public Milk(Coffee coffee) {
        super(coffee);
    }

    @Override
    public String getDescription() {
        return super.getDescription() + " + 牛奶";
    }

    @Override
    public double getCost() {
        return super.getCost() + 0.5;  // 牛奶价格 +0.5 元
    }
}

/**
 * 具体装饰器:糖(添加糖调料)
 */
public class Sugar extends CoffeeDecorator {
    public Sugar(Coffee coffee) {
        super(coffee);
    }

    @Override
    public String getDescription() {
        return super.getDescription() + " + 糖";
    }

    @Override
    public double getCost() {
        return super.getCost() + 0.3;  // 糖价格 +0.3 元
    }
}

5. 客户端调用

public class Client {
    public static void main(String[] args) {
        // 基础浓缩咖啡
        Coffee espresso = new Espresso();
        System.out.println(espresso.getDescription() + " 价格:" + espresso.getCost());

        // 为浓缩咖啡添加牛奶和糖
        Coffee decoratedCoffee = new Milk(espresso);
        decoratedCoffee = new Sugar(decoratedCoffee);
        System.out.println(decoratedCoffee.getDescription() + " 价格:" + decoratedCoffee.getCost());

        // 深焙咖啡 + 双倍糖
        Coffee darkRoast = new DarkRoast();
        darkRoast = new Sugar(darkRoast);
        darkRoast = new Sugar(darkRoast);
        System.out.println(darkRoast.getDescription() + " 价格:" + darkRoast.getCost());
    }
}

6. 输出结果

浓缩咖啡 价格:2.0
浓缩咖啡 + 牛奶 + 糖 价格:2.8
深焙咖啡 + 糖 + 糖 价格:3.1

五、模式结构图

+----------------+          +----------------+
|   Component    | <------+ |   Decorator    |
+----------------+          +----------------+
| +operation()   |          | -component:Component|
+----------------+          | +operation()   |
         ^                  +----------------+
         |                         ^
         |                         |
+----------------+          +----------------+
| ConcreteComponent        | ConcreteDecorator|
+----------------+          +----------------+
| +operation()   |          | +operation()   |
+----------------+          +----------------+

六、与其他模式的关系

  1. 适配器模式:装饰器增强对象功能,适配器改变接口。

  2. 组合模式:装饰器可视为只有一个组件的组合结构。

  3. 策略模式:装饰器动态改变对象行为,策略模式静态切换算法。


七、最佳实践

  1. 保持接口一致性:装饰器必须与组件接口一致,确保透明性。

  2. 控制装饰层数:避免过度装饰导致性能下降和代码混乱。

  3. 使用工厂模式:通过工厂管理装饰器的创建和组合逻辑。


八、总结

  • 核心价值:动态扩展对象功能,避免继承带来的静态局限性。

  • 适用场景:需灵活叠加功能的系统,如中间件、UI组件、I/O流处理。

  • 关键实现:组件接口 + 具体组件 + 抽象装饰器 + 具体装饰器。

装饰器模式在 Java 标准库中广泛应用,如 java.io.InputStream 的装饰器类(BufferedInputStreamDataInputStream)。掌握该模式可显著提升代码的扩展性和复用性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值