My App

装饰器模式

Decorator — 动态给对象增加功能,而不改变原始类

一句话理解

像"套娃"一样,在不修改原始对象的前提下,一层一层地给它叠加新功能

解决什么问题

  • 想给一个对象增加功能,但又不想改原始类
  • 如果用继承来扩展,子类数量会爆炸式增长(加糖咖啡、加奶咖啡、加糖加奶咖啡……)
  • 需要动态组合功能,而不是在编译期写死

怎么写

// 抽象组件
public interface Coffee {
    String getDescription();
    double getCost();
}

// 基础实现
public class SimpleCoffee implements Coffee {
    public String getDescription() { return "普通咖啡"; }
    public double getCost() { return 10.0; }
}

// 装饰器基类:也实现 Coffee 接口,内部持有一个 Coffee
public abstract class CoffeeDecorator implements Coffee {
    protected final Coffee coffee;
    public CoffeeDecorator(Coffee coffee) { this.coffee = coffee; }
}

// 具体装饰器
public class MilkDecorator extends CoffeeDecorator {
    public MilkDecorator(Coffee coffee) { super(coffee); }
    public String getDescription() { return coffee.getDescription() + " + 牛奶"; }
    public double getCost() { return coffee.getCost() + 3.0; }
}

public class SugarDecorator extends CoffeeDecorator {
    public SugarDecorator(Coffee coffee) { super(coffee); }
    public String getDescription() { return coffee.getDescription() + " + 糖"; }
    public double getCost() { return coffee.getCost() + 1.0; }
}
// 使用:像套娃一样层层包装
Coffee coffee = new SimpleCoffee();
coffee = new MilkDecorator(coffee);   // 加牛奶
coffee = new SugarDecorator(coffee);  // 再加糖

System.out.println(coffee.getDescription()); // 普通咖啡 + 牛奶 + 糖
System.out.println(coffee.getCost());        // 14.0

关键点:装饰器和被装饰对象实现相同的接口,所以可以无限嵌套。

前端中的装饰器

// TypeScript 装饰器(语法糖)
function Log(target: any, key: string, descriptor: PropertyDescriptor) {
  const original = descriptor.value
  descriptor.value = function (...args: any[]) {
    console.log(`调用 ${key},参数:`, args)
    return original.apply(this, args)
  }
}

class UserService {
  @Log
  getUser(id: number) { /* ... */ }
}
// React 高阶组件(HOC)也是装饰器思想
function withAuth(Component) {
  return function AuthWrapper(props) {
    if (!isLoggedIn()) return <LoginPage />
    return <Component {...props} />
  }
}

使用场景

  • Java I/O:new BufferedReader(new InputStreamReader(new FileInputStream("a.txt"))) 就是经典的装饰器嵌套
  • Spring 中的各种 Wrapper 类
  • Python 的 @decorator 语法
  • React 的高阶组件(HOC)
  • 中间件模式(Express/Koa)

On this page