Skip to content

装饰器模式 (Decorator Pattern)

概述

在不改变原有类的前提下,动态地为对象添加功能。

也就是说,用“包装”方式给对象增加功能,而不是修改原类或使用子类继承。

装饰器模式通过“包裹”的方式,为对象动态添加功能,是继承的强力替代方案,也是 Spring AOP、Java IO 等框架广泛应用的核心设计。

适用场景

  • 想增强类的功能,但不希望通过继承(继承会导致子类爆炸);

  • 需要在运行时动态添加/撤销功能;

  • 多个功能可以灵活组合(如 IO 流、文本格式、权限等);

  • 想遵循开闭原则:对扩展开放,对修改关闭。

类图结构

plaintext
        ┌───────────────┐
        │   Component   │  ← 抽象组件(定义接口)
        └───────┬───────┘

        ┌───────▼─────────┐
        │ ConcreteComponent│ ← 具体组件(原始对象)
        └───────┬──────────┘

        ┌───────▼────────────┐
        │   Decorator        │ ← 抽象装饰器,持有组件引用
        └───────┬────────────┘

        ┌───────▼───────────────┐
        │ ConcreteDecoratorA/B   │ ← 具体装饰器,实现增强功能
        └────────────────────────┘

核心组件

1. Component(抽象组件)

定义对象的接口,可以给这些对象动态地添加职责。

2. ConcreteComponent(具体组件)

定义一个对象,可以给这个对象添加一些职责。

3. Decorator(抽象装饰器)

维持一个指向Component对象的引用,并定义一个与Component接口一致的接口。

4. ConcreteDecorator(具体装饰器)

向组件添加职责。

实际代码示例

示例1:咖啡店订单系统

java
// 抽象组件:饮品接口
public interface Beverage {
    String getDescription();
    double getCost();
}

// 具体组件:基础咖啡
public class Espresso implements Beverage {
    @Override
    public String getDescription() {
        return "浓缩咖啡";
    }
    
    @Override
    public double getCost() {
        return 1.99;
    }
}

public class HouseBlend implements Beverage {
    @Override
    public String getDescription() {
        return "综合咖啡";
    }
    
    @Override
    public double getCost() {
        return 0.89;
    }
}

// 抽象装饰器
public abstract class CondimentDecorator implements Beverage {
    protected Beverage beverage;
    
    public CondimentDecorator(Beverage beverage) {
        this.beverage = beverage;
    }
    
    @Override
    public abstract String getDescription();
}

// 具体装饰器:牛奶
public class Milk extends CondimentDecorator {
    public Milk(Beverage beverage) {
        super(beverage);
    }
    
    @Override
    public String getDescription() {
        return beverage.getDescription() + ", 牛奶";
    }
    
    @Override
    public double getCost() {
        return beverage.getCost() + 0.10;
    }
}

// 具体装饰器:摩卡
public class Mocha extends CondimentDecorator {
    public Mocha(Beverage beverage) {
        super(beverage);
    }
    
    @Override
    public String getDescription() {
        return beverage.getDescription() + ", 摩卡";
    }
    
    @Override
    public double getCost() {
        return beverage.getCost() + 0.20;
    }
}

// 具体装饰器:豆浆
public class Soy extends CondimentDecorator {
    public Soy(Beverage beverage) {
        super(beverage);
    }
    
    @Override
    public String getDescription() {
        return beverage.getDescription() + ", 豆浆";
    }
    
    @Override
    public double getCost() {
        return beverage.getCost() + 0.15;
    }
}

// 具体装饰器:奶泡
public class Whip extends CondimentDecorator {
    public Whip(Beverage beverage) {
        super(beverage);
    }
    
    @Override
    public String getDescription() {
        return beverage.getDescription() + ", 奶泡";
    }
    
    @Override
    public double getCost() {
        return beverage.getCost() + 0.10;
    }
}

// 使用示例
public class CoffeeShop {
    public static void main(String[] args) {
        // 点一杯浓缩咖啡
        Beverage beverage = new Espresso();
        System.out.println(beverage.getDescription() + " $" + beverage.getCost());
        
        // 点一杯综合咖啡,加双倍摩卡,加奶泡
        Beverage beverage2 = new HouseBlend();
        beverage2 = new Mocha(beverage2);
        beverage2 = new Mocha(beverage2);
        beverage2 = new Whip(beverage2);
        System.out.println(beverage2.getDescription() + " $" + beverage2.getCost());
        
        // 点一杯浓缩咖啡,加豆浆,加摩卡,加奶泡
        Beverage beverage3 = new Espresso();
        beverage3 = new Soy(beverage3);
        beverage3 = new Mocha(beverage3);
        beverage3 = new Whip(beverage3);
        System.out.println(beverage3.getDescription() + " $" + beverage3.getCost());
    }
}

示例2:文本处理系统

java
// 抽象组件:文本处理接口
public interface TextProcessor {
    String process(String text);
}

// 具体组件:基础文本处理器
public class PlainTextProcessor implements TextProcessor {
    @Override
    public String process(String text) {
        return text;
    }
}

// 抽象装饰器
public abstract class TextDecorator implements TextProcessor {
    protected TextProcessor processor;
    
    public TextDecorator(TextProcessor processor) {
        this.processor = processor;
    }
    
    @Override
    public String process(String text) {
        return processor.process(text);
    }
}

// 具体装饰器:加密处理
public class EncryptionDecorator extends TextDecorator {
    public EncryptionDecorator(TextProcessor processor) {
        super(processor);
    }
    
    @Override
    public String process(String text) {
        String processedText = super.process(text);
        return encrypt(processedText);
    }
    
    private String encrypt(String text) {
        // 简单的加密实现(实际应用中应使用更安全的加密算法)
        StringBuilder encrypted = new StringBuilder();
        for (char c : text.toCharArray()) {
            encrypted.append((char) (c + 1));
        }
        return "[ENCRYPTED]" + encrypted.toString();
    }
}

// 具体装饰器:压缩处理
public class CompressionDecorator extends TextDecorator {
    public CompressionDecorator(TextProcessor processor) {
        super(processor);
    }
    
    @Override
    public String process(String text) {
        String processedText = super.process(text);
        return compress(processedText);
    }
    
    private String compress(String text) {
        // 简单的压缩实现(移除重复空格)
        String compressed = text.replaceAll("\\s+", " ").trim();
        return "[COMPRESSED]" + compressed;
    }
}

// 具体装饰器:Base64编码
public class Base64Decorator extends TextDecorator {
    public Base64Decorator(TextProcessor processor) {
        super(processor);
    }
    
    @Override
    public String process(String text) {
        String processedText = super.process(text);
        return encodeBase64(processedText);
    }
    
    private String encodeBase64(String text) {
        // 使用Java 8的Base64编码
        return "[BASE64]" + java.util.Base64.getEncoder().encodeToString(text.getBytes());
    }
}

// 具体装饰器:日志记录
public class LoggingDecorator extends TextDecorator {
    public LoggingDecorator(TextProcessor processor) {
        super(processor);
    }
    
    @Override
    public String process(String text) {
        System.out.println("处理文本: " + text.substring(0, Math.min(text.length(), 20)) + "...");
        String result = super.process(text);
        System.out.println("处理完成,结果长度: " + result.length());
        return result;
    }
}

// 使用示例
public class TextProcessingDemo {
    public static void main(String[] args) {
        String originalText = "这是一个需要处理的文本内容,包含多个空格   和特殊字符!";
        
        // 基础处理
        TextProcessor processor = new PlainTextProcessor();
        System.out.println("原始: " + processor.process(originalText));
        
        // 添加压缩功能
        processor = new CompressionDecorator(processor);
        System.out.println("压缩: " + processor.process(originalText));
        
        // 添加加密功能
        processor = new EncryptionDecorator(processor);
        System.out.println("加密: " + processor.process(originalText));
        
        // 添加Base64编码
        processor = new Base64Decorator(processor);
        System.out.println("Base64: " + processor.process(originalText));
        
        // 添加日志记录
        processor = new LoggingDecorator(processor);
        System.out.println("\n最终处理结果:");
        String finalResult = processor.process(originalText);
        System.out.println(finalResult);
    }
}

优缺点分析

优点

  1. 灵活性高

    • 可以在运行时动态添加或移除功能
    • 支持多种装饰器的任意组合
    • 比继承更加灵活
  2. 遵循开闭原则

    • 对扩展开放:可以轻松添加新的装饰器
    • 对修改关闭:不需要修改现有代码
  3. 避免类爆炸

    • 不需要为每种功能组合创建子类
    • 通过组合而非继承实现功能扩展
  4. 单一职责原则

    • 每个装饰器只负责一种功能的增强
    • 功能职责清晰分离
  5. 透明性

    • 装饰器和被装饰对象实现相同接口
    • 客户端无需知道对象是否被装饰

缺点

  1. 复杂性增加

    • 多层装饰可能导致调试困难
    • 对象创建过程变得复杂
  2. 性能开销

    • 每个装饰器都会增加一层方法调用
    • 多层装饰可能影响性能
  3. 装饰顺序敏感

    • 不同的装饰顺序可能产生不同的结果
    • 需要仔细考虑装饰器的应用顺序
  4. 类型识别困难

    • 被多层装饰的对象难以进行类型检查
    • instanceof操作可能不如预期

与其他模式的对比

装饰器模式 vs 适配器模式

特性装饰器模式适配器模式
目的增强对象功能接口转换
接口保持原接口不变转换为新接口
功能添加新功能使不兼容接口兼容
透明性对客户端透明客户端知道适配过程

装饰器模式 vs 代理模式

特性装饰器模式代理模式
目的增强功能控制访问
关注点功能扩展访问控制、延迟加载等
透明性完全透明可能不透明
组合支持多层装饰通常单层代理

装饰器模式 vs 策略模式

特性装饰器模式策略模式
目的动态添加功能算法选择
结构包装结构组合结构
运行时可动态组合可动态切换
功能功能叠加功能替换

实际应用场景

1. Java I/O流

java
// Java I/O是装饰器模式的经典应用
FileInputStream fis = new FileInputStream("data.txt");
BufferedInputStream bis = new BufferedInputStream(fis);
DataInputStream dis = new DataInputStream(bis);

// 每一层都添加了新的功能:
// FileInputStream: 基础文件读取
// BufferedInputStream: 添加缓冲功能
// DataInputStream: 添加数据类型读取功能

2. Spring AOP

java
// Spring AOP通过装饰器模式实现切面编程
@Service
public class UserService {
    @Transactional  // 事务装饰器
    @Cacheable     // 缓存装饰器
    @Logged        // 日志装饰器
    public User getUserById(Long id) {
        return userRepository.findById(id);
    }
}

3. Web中间件

java
// Express.js风格的中间件
public interface Middleware {
    void handle(Request request, Response response, Runnable next);
}

public class AuthenticationMiddleware implements Middleware {
    private Middleware next;
    
    public AuthenticationMiddleware(Middleware next) {
        this.next = next;
    }
    
    @Override
    public void handle(Request request, Response response, Runnable nextCallback) {
        if (isAuthenticated(request)) {
            if (next != null) {
                next.handle(request, response, nextCallback);
            } else {
                nextCallback.run();
            }
        } else {
            response.setStatus(401);
            response.setBody("Unauthorized");
        }
    }
    
    private boolean isAuthenticated(Request request) {
        return request.getHeader("Authorization") != null;
    }
}

public class LoggingMiddleware implements Middleware {
    private Middleware next;
    
    public LoggingMiddleware(Middleware next) {
        this.next = next;
    }
    
    @Override
    public void handle(Request request, Response response, Runnable nextCallback) {
        System.out.println("请求: " + request.getPath());
        long startTime = System.currentTimeMillis();
        
        if (next != null) {
            next.handle(request, response, () -> {
                long endTime = System.currentTimeMillis();
                System.out.println("响应: " + response.getStatus() + ", 耗时: " + (endTime - startTime) + "ms");
                nextCallback.run();
            });
        } else {
            nextCallback.run();
        }
    }
}

4. GUI组件装饰

java
// GUI组件的装饰器应用
public interface Component {
    void draw();
    int getWidth();
    int getHeight();
}

public class Window implements Component {
    private int width, height;
    
    public Window(int width, int height) {
        this.width = width;
        this.height = height;
    }
    
    @Override
    public void draw() {
        System.out.println("绘制窗口 (" + width + "x" + height + ")");
    }
    
    @Override
    public int getWidth() { return width; }
    
    @Override
    public int getHeight() { return height; }
}

public abstract class ComponentDecorator implements Component {
    protected Component component;
    
    public ComponentDecorator(Component component) {
        this.component = component;
    }
    
    @Override
    public void draw() {
        component.draw();
    }
    
    @Override
    public int getWidth() {
        return component.getWidth();
    }
    
    @Override
    public int getHeight() {
        return component.getHeight();
    }
}

public class BorderDecorator extends ComponentDecorator {
    private int borderWidth;
    
    public BorderDecorator(Component component, int borderWidth) {
        super(component);
        this.borderWidth = borderWidth;
    }
    
    @Override
    public void draw() {
        super.draw();
        System.out.println("添加边框 (宽度: " + borderWidth + ")");
    }
    
    @Override
    public int getWidth() {
        return super.getWidth() + 2 * borderWidth;
    }
    
    @Override
    public int getHeight() {
        return super.getHeight() + 2 * borderWidth;
    }
}

public class ScrollDecorator extends ComponentDecorator {
    public ScrollDecorator(Component component) {
        super(component);
    }
    
    @Override
    public void draw() {
        super.draw();
        System.out.println("添加滚动条");
    }
    
    @Override
    public int getWidth() {
        return super.getWidth() + 20; // 滚动条宽度
    }
}

模式变种和扩展

1. 透明装饰器模式

java
// 透明装饰器:装饰器和组件有相同的接口
public interface Shape {
    void draw();
    double getArea();
}

public class Circle implements Shape {
    private double radius;
    
    public Circle(double radius) {
        this.radius = radius;
    }
    
    @Override
    public void draw() {
        System.out.println("绘制圆形,半径: " + radius);
    }
    
    @Override
    public double getArea() {
        return Math.PI * radius * radius;
    }
}

public abstract class ShapeDecorator implements Shape {
    protected Shape shape;
    
    public ShapeDecorator(Shape shape) {
        this.shape = shape;
    }
    
    @Override
    public void draw() {
        shape.draw();
    }
    
    @Override
    public double getArea() {
        return shape.getArea();
    }
}

public class ColorDecorator extends ShapeDecorator {
    private String color;
    
    public ColorDecorator(Shape shape, String color) {
        super(shape);
        this.color = color;
    }
    
    @Override
    public void draw() {
        super.draw();
        System.out.println("添加颜色: " + color);
    }
}

2. 半透明装饰器模式

java
// 半透明装饰器:装饰器可能添加新的方法
public interface DataSource {
    void writeData(String data);
    String readData();
}

public class FileDataSource implements DataSource {
    private String filename;
    private String data = "";
    
    public FileDataSource(String filename) {
        this.filename = filename;
    }
    
    @Override
    public void writeData(String data) {
        this.data = data;
        System.out.println("写入文件 " + filename + ": " + data);
    }
    
    @Override
    public String readData() {
        System.out.println("从文件 " + filename + " 读取数据");
        return data;
    }
}

public abstract class DataSourceDecorator implements DataSource {
    protected DataSource dataSource;
    
    public DataSourceDecorator(DataSource dataSource) {
        this.dataSource = dataSource;
    }
    
    @Override
    public void writeData(String data) {
        dataSource.writeData(data);
    }
    
    @Override
    public String readData() {
        return dataSource.readData();
    }
}

public class EncryptionDecorator extends DataSourceDecorator {
    public EncryptionDecorator(DataSource dataSource) {
        super(dataSource);
    }
    
    @Override
    public void writeData(String data) {
        super.writeData(encrypt(data));
    }
    
    @Override
    public String readData() {
        return decrypt(super.readData());
    }
    
    // 新增方法:获取加密状态
    public boolean isEncrypted() {
        return true;
    }
    
    // 新增方法:获取加密算法
    public String getEncryptionAlgorithm() {
        return "AES-256";
    }
    
    private String encrypt(String data) {
        return "[ENCRYPTED]" + data;
    }
    
    private String decrypt(String data) {
        return data.replace("[ENCRYPTED]", "");
    }
}

3. 函数式装饰器

java
// 使用函数式接口实现装饰器
@FunctionalInterface
public interface Function<T, R> {
    R apply(T input);
    
    // 默认方法:组合装饰器
    default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
        return (T t) -> after.apply(apply(t));
    }
    
    default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
        return (V v) -> apply(before.apply(v));
    }
}

// 函数式装饰器示例
public class FunctionalDecoratorDemo {
    public static void main(String[] args) {
        // 基础函数
        Function<String, String> base = text -> text.toUpperCase();
        
        // 装饰器函数
        Function<String, String> addPrefix = text -> "PREFIX: " + text;
        Function<String, String> addSuffix = text -> text + " :SUFFIX";
        Function<String, String> addBrackets = text -> "[" + text + "]";
        
        // 组合装饰器
        Function<String, String> decorated = base
            .andThen(addPrefix)
            .andThen(addSuffix)
            .andThen(addBrackets);
        
        String result = decorated.apply("hello world");
        System.out.println(result); // [PREFIX: HELLO WORLD :SUFFIX]
    }
}

最佳实践

1. 装饰器设计原则

java
// 良好的装饰器基类设计
public abstract class BaseDecorator<T> {
    protected final T component;
    
    public BaseDecorator(T component) {
        if (component == null) {
            throw new IllegalArgumentException("Component cannot be null");
        }
        this.component = component;
    }
    
    // 提供获取原始组件的方法
    public T getComponent() {
        return component;
    }
    
    // 提供解包装方法
    @SuppressWarnings("unchecked")
    public <U> U unwrap(Class<U> type) {
        if (type.isInstance(this)) {
            return (U) this;
        }
        if (component instanceof BaseDecorator) {
            return ((BaseDecorator<?>) component).unwrap(type);
        }
        if (type.isInstance(component)) {
            return (U) component;
        }
        return null;
    }
    
    // 检查是否包含特定类型的装饰器
    public boolean hasDecorator(Class<?> decoratorType) {
        return unwrap(decoratorType) != null;
    }
}

2. 装饰器工厂

java
// 装饰器工厂,简化装饰器的创建和组合
public class DecoratorFactory {
    
    public static TextProcessor createTextProcessor(String... decorators) {
        TextProcessor processor = new PlainTextProcessor();
        
        for (String decorator : decorators) {
            processor = createDecorator(decorator, processor);
        }
        
        return processor;
    }
    
    private static TextProcessor createDecorator(String type, TextProcessor processor) {
        switch (type.toLowerCase()) {
            case "encryption":
                return new EncryptionDecorator(processor);
            case "compression":
                return new CompressionDecorator(processor);
            case "base64":
                return new Base64Decorator(processor);
            case "logging":
                return new LoggingDecorator(processor);
            default:
                throw new IllegalArgumentException("Unknown decorator type: " + type);
        }
    }
    
    // 建造者模式结合装饰器
    public static class TextProcessorBuilder {
        private TextProcessor processor;
        
        public TextProcessorBuilder() {
            this.processor = new PlainTextProcessor();
        }
        
        public TextProcessorBuilder withEncryption() {
            this.processor = new EncryptionDecorator(processor);
            return this;
        }
        
        public TextProcessorBuilder withCompression() {
            this.processor = new CompressionDecorator(processor);
            return this;
        }
        
        public TextProcessorBuilder withBase64() {
            this.processor = new Base64Decorator(processor);
            return this;
        }
        
        public TextProcessorBuilder withLogging() {
            this.processor = new LoggingDecorator(processor);
            return this;
        }
        
        public TextProcessor build() {
            return processor;
        }
    }
}

// 使用示例
public class DecoratorFactoryDemo {
    public static void main(String[] args) {
        // 使用工厂方法
        TextProcessor processor1 = DecoratorFactory.createTextProcessor(
            "compression", "encryption", "base64", "logging"
        );
        
        // 使用建造者模式
        TextProcessor processor2 = new DecoratorFactory.TextProcessorBuilder()
            .withCompression()
            .withEncryption()
            .withBase64()
            .withLogging()
            .build();
        
        String text = "Hello, Decorator Pattern!";
        System.out.println(processor1.process(text));
        System.out.println(processor2.process(text));
    }
}

3. 性能优化策略

java
// 缓存装饰器:避免重复计算
public class CachingDecorator extends TextDecorator {
    private final Map<String, String> cache = new ConcurrentHashMap<>();
    private final int maxCacheSize;
    
    public CachingDecorator(TextProcessor processor, int maxCacheSize) {
        super(processor);
        this.maxCacheSize = maxCacheSize;
    }
    
    @Override
    public String process(String text) {
        return cache.computeIfAbsent(text, key -> {
            if (cache.size() >= maxCacheSize) {
                // 简单的LRU策略:清除一半缓存
                cache.clear();
            }
            return super.process(key);
        });
    }
    
    public void clearCache() {
        cache.clear();
    }
    
    public int getCacheSize() {
        return cache.size();
    }
}

// 异步装饰器:提高性能
public class AsyncDecorator extends TextDecorator {
    private final ExecutorService executor;
    
    public AsyncDecorator(TextProcessor processor, ExecutorService executor) {
        super(processor);
        this.executor = executor;
    }
    
    public CompletableFuture<String> processAsync(String text) {
        return CompletableFuture.supplyAsync(() -> super.process(text), executor);
    }
    
    @Override
    public String process(String text) {
        try {
            return processAsync(text).get();
        } catch (InterruptedException | ExecutionException e) {
            throw new RuntimeException("异步处理失败", e);
        }
    }
}

4. 错误处理和监控

java
// 错误处理装饰器
public class ErrorHandlingDecorator extends TextDecorator {
    private final ErrorHandler errorHandler;
    
    public ErrorHandlingDecorator(TextProcessor processor, ErrorHandler errorHandler) {
        super(processor);
        this.errorHandler = errorHandler;
    }
    
    @Override
    public String process(String text) {
        try {
            return super.process(text);
        } catch (Exception e) {
            return errorHandler.handle(text, e);
        }
    }
    
    @FunctionalInterface
    public interface ErrorHandler {
        String handle(String originalText, Exception error);
    }
}

// 监控装饰器
public class MonitoringDecorator extends TextDecorator {
    private final AtomicLong processCount = new AtomicLong(0);
    private final AtomicLong totalProcessingTime = new AtomicLong(0);
    private final AtomicLong errorCount = new AtomicLong(0);
    
    public MonitoringDecorator(TextProcessor processor) {
        super(processor);
    }
    
    @Override
    public String process(String text) {
        long startTime = System.nanoTime();
        try {
            String result = super.process(text);
            processCount.incrementAndGet();
            return result;
        } catch (Exception e) {
            errorCount.incrementAndGet();
            throw e;
        } finally {
            long endTime = System.nanoTime();
            totalProcessingTime.addAndGet(endTime - startTime);
        }
    }
    
    public long getProcessCount() {
        return processCount.get();
    }
    
    public double getAverageProcessingTime() {
        long count = processCount.get();
        return count > 0 ? (double) totalProcessingTime.get() / count / 1_000_000 : 0; // 毫秒
    }
    
    public long getErrorCount() {
        return errorCount.get();
    }
    
    public double getErrorRate() {
        long total = processCount.get() + errorCount.get();
        return total > 0 ? (double) errorCount.get() / total : 0;
    }
}

总结

装饰器模式是一种非常实用的结构型设计模式,它通过组合而非继承的方式为对象动态添加功能。这种模式在现代软件开发中有着广泛的应用,从Java的I/O流到Spring的AOP,从Web中间件到GUI组件,都能看到装饰器模式的身影。

核心价值

  1. 灵活性:运行时动态添加功能,支持任意组合
  2. 可扩展性:遵循开闭原则,易于添加新功能
  3. 可维护性:职责分离,每个装饰器专注单一功能
  4. 透明性:对客户端完全透明,无需修改现有代码

使用建议

  1. 适度使用:避免过度装饰导致的复杂性
  2. 注意顺序:装饰器的应用顺序可能影响最终结果
  3. 性能考虑:多层装饰可能带来性能开销
  4. 错误处理:提供完善的错误处理机制
  5. 监控调试:为复杂的装饰器链提供监控和调试支持

装饰器模式是面向对象设计中"组合优于继承"原则的完美体现,它为我们提供了一种优雅的方式来扩展对象功能,是每个开发者都应该掌握的重要设计模式。