自学内容网 自学内容网

装饰器模式 (Decorator Pattern)

装饰器模式 (Decorator Pattern)

装饰器模式是一种 结构型设计模式,它允许动态地向对象添加新的功能,同时又不改变其结构。这种模式通过对象组合来实现,比通过继承扩展功能更加灵活。


原理

  1. 核心思想:通过将对象包装在一系列装饰器中,增强或修改对象的功能,而无需更改对象本身的代码。
  2. 适用场景
    • 希望动态地扩展一个类的功能,而不使用继承。
    • 需要为一个对象提供多种行为组合,且行为的数量动态变化。
  3. 参与角色
    • Component(抽象组件):定义一个对象接口,可以动态地为其添加职责。
    • ConcreteComponent(具体组件):实现抽象组件的类,是被装饰的对象。
    • Decorator(装饰器):实现抽象组件,并持有一个具体组件的引用。
    • ConcreteDecorator(具体装饰器):扩展装饰器,提供额外的功能。

优点

  1. 动态扩展功能:无需修改原始类和其他装饰器类即可扩展功能。
  2. 遵循开闭原则:通过添加新装饰器类来实现功能扩展。
  3. 灵活组合:装饰器可以任意组合使用。

缺点

  1. 复杂性增加:过多的装饰器可能导致系统变得复杂。
  2. 调试困难:在装饰器链中定位问题可能较为困难。

示例代码

场景描述

假设有一个咖啡订单系统,不同的咖啡可以加不同的调料(如牛奶、糖)。咖啡本身和调料的价格需要动态组合计算,且系统应具备良好的扩展性。


1. 定义抽象组件
// 抽象组件
public interface Coffee {
    String getDescription(); // 获取描述
    double getCost();        // 获取价格
}

2. 创建具体组件
// 具体组件:基础咖啡
public class BasicCoffee implements Coffee {
    @Override
    public String getDescription() {
        return "Basic Coffee";
    }

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

3. 创建装饰器抽象类
// 抽象装饰器
public abstract class CoffeeDecorator implements Coffee {
    protected Coffee coffee; // 持有组件的引用

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

    @Override
    public String getDescription() {
        return coffee.getDescription();
    }

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

4. 创建具体装饰器
// 牛奶装饰器
public class MilkDecorator extends CoffeeDecorator {
    public MilkDecorator(Coffee coffee) {
        super(coffee);
    }

    @Override
    public String getDescription() {
        return coffee.getDescription() + ", Milk";
    }

    @Override
    public double getCost() {
        return coffee.getCost() + 1.5; // 牛奶价格
    }
}

// 糖装饰器
public class SugarDecorator extends CoffeeDecorator {
    public SugarDecorator(Coffee coffee) {
        super(coffee);
    }

    @Override
    public String getDescription() {
        return coffee.getDescription() + ", Sugar";
    }

    @Override
    public double getCost() {
        return coffee.getCost() + 0.5; // 糖价格
    }
}

5. 客户端代码
public class DecoratorPatternExample {
    public static void main(String[] args) {
        // 基础咖啡
        Coffee coffee = new BasicCoffee();
        System.out.println(coffee.getDescription() + " -> $" + coffee.getCost());

        // 加牛奶的咖啡
        coffee = new MilkDecorator(coffee);
        System.out.println(coffee.getDescription() + " -> $" + coffee.getCost());

        // 加牛奶和糖的咖啡
        coffee = new SugarDecorator(coffee);
        System.out.println(coffee.getDescription() + " -> $" + coffee.getCost());
    }
}

输出结果
Basic Coffee -> $5.0
Basic Coffee, Milk -> $6.5
Basic Coffee, Milk, Sugar -> $7.0

UML 类图

         +----------------+         +--------------------+
         |    Coffee      |<>------>|  CoffeeDecorator   |
         +----------------+         +--------------------+
         |+ getDescription()        |+ getDescription()  |
         |+ getCost()               |+ getCost()         |
         +----------------+         +--------------------+
                ^                           ^
                |                           |
   +--------------------+         +--------------------+
   |   BasicCoffee      |         | MilkDecorator      |
   +--------------------+         +--------------------+
   |+ getDescription()  |         |+ getDescription()  |
   |+ getCost()         |         |+ getCost()         |
   +--------------------+         +--------------------+

使用场景

  1. 需要动态地增加功能:如图形编辑器中为图形对象添加功能(边框、阴影)。
  2. 功能组合的场景:如不同装饰效果的叠加。
  3. 避免继承扩展:用装饰器动态扩展功能而不引入过多的子类。

总结

  • 装饰器模式是一种灵活的设计模式,可以在运行时动态地为对象添加功能。
  • 它有效避免了类爆炸问题,特别适合需要灵活组合的场景。
  • 通过对象组合,装饰器模式实现了强大的扩展能力,符合 开闭原则

原文地址:https://blog.csdn.net/qq_35861084/article/details/143960882

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!