结构型:装饰器模式

发布于:2025-05-25 ⋅ 阅读:(28) ⋅ 点赞:(0)

目录

1、核心思想

2、实现方式

2.1 模式结构

2.2 实现案例

3、优缺点分析

4、适用场景


1、核心思想

目的:在不改变其原始结构的前提下使客体功能得到扩展、增强。

核心:组合替代继承

举例:

1> 化妆:通过对素颜的人,进行顺序不确定的各种步骤(粉底、口红、睫毛膏等)的化妆,从而达到想要的结果

2> “java.io”包里一系列的流处理类InputStream、FileInputStream、BufferedInputStream、ZipInputStream等

File file = new File("/压缩包.zip");
//开始装饰
ZipInputStream zipInputStream = new ZipInputStream(
    new BufferedInputStream(
        new FileInputStream(file)
    )
)

首先以文件file初始化并构造文件输入流FileInputStream,然后外层用缓冲输入流BufferedInputStream进行装饰,使文件输入流具备内存缓冲的功能,最外层再用压缩包输入流ZipInputStream进行最终装饰,使文件输入流具备Zip格式文件的功能,之后我们就可以对压缩包进行解压操作了

3> GUI组件:为按钮添加边框、滚动条等动态效果

4> Web中间件:请求处理链中的身份验证、日志记录、压缩等装饰逻辑

2、实现方式

2.1 模式结构

四个核心角色:

  • Component(组件接口)​:所有被装饰组件及装饰器对应的接口标准,指定进行装饰的行为方法。
  • ConcreteComponent(组件实现)​:被装饰组件,实现组件接口,是被装饰的原始对象。
  • Decorator(装饰器)​:装饰器的高层抽象类,同样实现组件接口标准,且包含一个被装饰的组件。
  • ConcreteDecorator(装饰器实现)​:继承自装饰器抽象类的具体子类装饰器,可以有多种实现,在被装饰组件对象的基础上为其添加新的特性。

2.2 实现案例

咖啡店提供基础咖啡(如美式咖啡),并支持动态添加牛奶、糖等配料,价格和描述需随配料叠加。

// 1、组件接口
interface Coffee {
    double getCost();
    String getDescription();
}

// 2、具体组件:基础咖啡
class SimpleCoffee implements Coffee {
    @Override
    public double getCost() { return 2.0; }
    @Override
    public String getDescription() { return "美式咖啡"; }
}

// 3、装饰器基类
abstract class CoffeeDecorator implements Coffee {
    protected Coffee decoratedCoffee;//被装饰组件变量(基础组件)
    public CoffeeDecorator(Coffee coffee) { this.decoratedCoffee = coffee; }
}

// 4、具体装饰器:加牛奶
class MilkDecorator extends CoffeeDecorator {
    public MilkDecorator(Coffee coffee) { super(coffee); }

    @Override
    public double getCost() {
        return decoratedCoffee.getCost() + 0.5; // 叠加牛奶价格
    }

    @Override
    public String getDescription() {
        return decoratedCoffee.getDescription() + " + 牛奶"; // 叠加描述
    }
}

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

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

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

// 客户端调用
public class Client {
    public static void main(String[] args) {
        Coffee coffee = new SimpleCoffee();
        coffee = new MilkDecorator(coffee); // 动态装饰
        coffee = new SugarDecorator(coffee);

        System.out.println("订单: " + coffee.getDescription());
        System.out.println("总价: $" + coffee.getCost());
    }
}

输出:

订单: 美式咖啡 + 牛奶 + 糖
总价: $2.7

3、优缺点分析

优点:

  1. 动态扩展功能:无需修改原有代码,通过嵌套装饰器灵活组合功能。

  2. 避免类爆炸:替代多层次的继承结构(如CoffeeWithMilkAndSugarCoffeeWithMilk等子类)。

  3. 单一职责原则:每个装饰器仅关注一个功能点。

  4. 开闭原则:支持扩展新装饰器,且不修改现有代码。

缺点:

  1. 复杂度增加:多层装饰可能导致对象链难以跟踪和调试。

  2. 冗余代码:需为每个装饰器实现组件接口的所有方法(即使仅增强部分逻辑)。

  3. 初始化繁琐:创建对象时需逐层包装装饰器。

4、适用场景

  • 动态功能扩展

    • 为对象添加日志、缓存、权限校验等非核心功能。

    • 如Java I/O流(BufferedInputStream装饰FileInputStream)。

  • 不可继承的场景

    • 当目标类被final修饰,或已有复杂的继承层次时。

  • 撤销功能需求

    • 通过移除装饰器回退到原始状态(需自行管理装饰链)。


网站公告

今日签到

点亮在社区的每一天
去签到