装饰器模式

装饰器(Decorator、Wrapper)模式属于结构型模式的一种。

装饰器模式是动态地给一个对象添加一些额外的职责。

装饰器模式的目的就是把一个一个的附加功能,给一层一层地累加在原始类上。

装饰器模式通常用于系统需要在运行时增加功能的场景,同时避免子类化和扩展原有类的复杂性。

装饰器本身可以继续装饰其他装饰器,从而形成装饰链

装饰器模式提供了一种在运行时动态增加功能的方式,而无需修改原始对象的代码。

封装器是装饰模式的别称,封装器实现了与其封装对象相同的接口。我们可以将一个对象放入多个封装器中,并在对象中添加所有这些封装器的组合行为。

只要所有装饰都遵循相同的接口, 客户端就可以使用任意自定义的装饰来装饰对象。

在现实生活中,穿衣服就是使用装饰的一个例子。冷,可以穿秋裤,穿上秋裤还冷,可以穿毛裤,下雨还可以穿上雨衣。所有这些衣物都 “扩展” 了我们的基本行为, 但它们并不是我们的一部分, 如果我们不再需要某件衣物, 可以方便地随时脱掉。

装饰器模式通常有以下组成部分:

  • Component(组件):定义一个接口或抽象类,所有具体组件和装饰器都必须遵循这个接口。
  • ConcreteComponent(具体组件):实现了 Component 接口,定义了一个基础的对象,可以通过装饰器为其添加额外功能。
  • Decorator(装饰器):实现了 Component 接口,持有一个 Component 对象的引用,并在 Component 的基础上添加额外功能。
  • ConcreteDecorator(具体装饰器):具体的装饰器,继承自 Decorator,并且定义了具体的装饰行为,如改变行为。

使用装饰器模式来给咖啡添加牛奶和糖。

1、Component(组件)接口

// Component(组件)接口
interface Coffee {
    double cost(); // 获取咖啡的价格
}

2、ConcreteComponent(具体组件)

// ConcreteComponent(具体组件)
class SimpleCoffee implements Coffee {
    @Override
    public double cost() {
        return 5.0;  // 基础咖啡的价格
    }
}

3、Decorator(装饰器)类

// Decorator(装饰器)类,继承自 Coffee
abstract class CoffeeDecorator implements Coffee {
    protected Coffee coffee; // 持有一个 Coffee 对象的引用

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

    @Override
    public double cost() {
        return coffee.cost(); // 委托给被装饰的对象
    }
}

4、ConcreteDecorator(具体装饰器)

// ConcreteDecorator(具体装饰器)- 添加牛奶
class MilkDecorator extends CoffeeDecorator {
    public MilkDecorator(Coffee coffee) {
        super(coffee); // 通过构造方法将原始对象传入
    }

    @Override
    public double cost() {
        return coffee.cost() + 1.0; // 加牛奶后,增加1元
    }
}

// ConcreteDecorator(具体装饰器)- 添加糖
class SugarDecorator extends CoffeeDecorator {
    public SugarDecorator(Coffee coffee) {
        super(coffee); // 通过构造方法将原始对象传入
    }

    @Override
    public double cost() {
        return coffee.cost() + 0.5; // 加糖后,增加0.5元
    }
}

5、客户端

// 测试装饰器模式
public class DecoratorPatternDemo {
    public static void main(String[] args) {
        Coffee simpleCoffee = new SimpleCoffee(); // 基础咖啡
        System.out.println("Base Coffee cost: " + simpleCoffee.cost()); // 输出基础咖啡的价格

        Coffee coffeeWithMilk = new MilkDecorator(simpleCoffee); // 加牛奶
        System.out.println("Coffee with Milk cost: " + coffeeWithMilk.cost()); // 输出加牛奶后的价格

        Coffee coffeeWithMilkAndSugar = new SugarDecorator(coffeeWithMilk); // 加糖
        System.out.println("Coffee with Milk and Sugar cost: " + coffeeWithMilkAndSugar.cost()); // 输出加牛奶和糖后的价格
    }
}

装饰器模式的优缺点

优点:

  • 把核心功能和附加功能分开了,两部分都可以进行独立地扩展。
  • 增加功能的灵活性:能够在运行时动态地添加功能,而不需要修改现有代码。
  • 避免子类化的繁琐:可以通过多层装饰器来组合功能,而无需通过继承产生大量的子类。

缺点:

  • 多层装饰器导致复杂性增加:装饰器层级较多时,可能会导致系统结构复杂,调试和理解代码变得困难。
  • 性能开销:每添加一个装饰器,都会增加一次方法调用的开销,尤其是在装饰器层级较多时,性能可能受到影响。

如果希望在无需修改代码的情况下即可使用对象,且希望在运行时为对象新增额外的行为, 可以使用装饰模式。

适配器能为被封装对象提供不同的接口,代理模式能为对象提供相同的接口,装饰则能为对象提供加强的接口。

不为障碍所困,紧盯目标;不为时间所迷,物尽其用;不为思维所限,向前一步。-- 烟沙九洲

 
 
posted @ 2024-11-27 20:52  烟沙九洲  阅读(19)  评论(0编辑  收藏  举报  来源