我就是奇迹

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

装饰器模式(Decorator Pattern)

 

装饰器模式结构型设计模式 之一,它允许你动态地给对象添加新的功能,而无需修改其原始代码。装饰器模式通常用于扩展类的功能,而不使用继承


 

1. 装饰器模式的核心思想

继承 vs. 装饰器模式

继承:创建子类来扩展功能,但可能会导致子类膨胀(类爆炸问题)。

装饰器模式:使用对象组合(composition),在运行时动态添加行为,比继承更加灵活。

关键点

1. 装饰器(Decorator)和被装饰的对象(Component)必须有相同的接口,这样装饰器就可以替换原始对象。

2. 装饰器持有一个被装饰对象的引用,并在调用方法时增强原有功能

 


 

2. 代码示例(Java 实现)

 

假设我们有一个 Coffee 接口,表示一杯咖啡,我们想要动态地添加牛奶、糖等配料,而不直接修改 Coffee 类。

 

(1)定义组件接口

// 抽象组件
public interface Coffee {
    String getDescription();  // 获取描述
    double cost();            // 计算价格
}

(2)实现基础组件

// 具体组件:普通咖啡
public class SimpleCoffee implements Coffee {
    @Override
    public String getDescription() {
        return "普通咖啡";
    }

    @Override
    public double cost() {
        return 10.0; // 普通咖啡价格
    }
}

(3)创建抽象装饰器

// 抽象装饰器
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 cost() {
        return decoratedCoffee.cost();
    }
}

(4)实现具体装饰器

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

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

    @Override
    public double cost() {
        return super.cost() + 3.0; // 牛奶价格
    }
}

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

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

    @Override
    public double cost() {
        return super.cost() + 2.0; // 糖的价格
    }
}

(5)测试装饰器模式

public class DecoratorPatternTest {
    public static void main(String[] args) {
        Coffee coffee = new SimpleCoffee();
        System.out.println(coffee.getDescription() + " 价格:" + coffee.cost());

        // 加牛奶
        coffee = new MilkDecorator(coffee);
        System.out.println(coffee.getDescription() + " 价格:" + coffee.cost());

        // 加糖
        coffee = new SugarDecorator(coffee);
        System.out.println(coffee.getDescription() + " 价格:" + coffee.cost());
    }
}

(6)运行结果

普通咖啡 价格:10.0
普通咖啡 + 牛奶 价格:13.0
普通咖啡 + 牛奶 + 糖 价格:15.0

装饰器模式让我们在不修改 Coffee 类的情况下,动态地增加功能!

 


 

3. 装饰器模式 vs. 继承

对比项

继承

装饰器模式

扩展方式

通过子类扩展

通过组合对象

灵活性

需要创建多个子类

运行时动态组合多个装饰器

类膨胀问题

过多子类可能导致类爆炸

解决类膨胀问题

适用于

静态扩展(编译时确定)

运行时动态扩展

 

 


 

4. Spring 框架中的应用

 

Spring 使用装饰器模式的地方很多,比如:

HttpServletRequestWrapper / HttpServletResponseWrapper:用于包装 HTTP 请求和响应,增强其功能。

Spring AOP(Aspect-Oriented Programming):用于动态代理,在方法调用前后插入增强逻辑,比如日志记录、事务管理等。

Spring Security:用于动态添加安全检查,比如权限认证、CSRF 保护等。

 


 

5. 总结

装饰器模式用于动态扩展对象功能,而不修改原有类。

相比继承,装饰器模式更加灵活,可组合多个功能。

在 Java、Spring、设计模式中,装饰器模式被广泛使用。

posted on 2025-04-02 17:52  我就是奇迹  阅读(144)  评论(0)    收藏  举报