装饰器模式(Decorator Pattern)

装饰器模式概述

装饰器模式是一种结构型设计模式,允许在不修改对象结构的前提下动态扩展功能。该模式通过包装对象实现功能增强,避免了继承带来的局限性。

核心思想

装饰器模式的核心原则包括:

  • 动态扩展:运行时灵活添加新功能
  • 接口一致:装饰器与被装饰对象保持相同接口
  • 组合优先:采用对象组合而非继承实现扩展
  • 职责单一:每个装饰器仅关注单一功能扩展

典型结构

1. 抽象组件(Component)

java 复制代码
public interface Coffee {
    String getDescription();
    double getCost();
}

2. 具体组件(ConcreteComponent)

java 复制代码
public class SimpleCoffee implements Coffee {
    @Override
    public String getDescription() {
        return "Simple Coffee";
    }
    
    @Override
    public double getCost() {
        return 2.0;
    }
}

3. 抽象装饰器(Decorator)

java 复制代码
public abstract class CoffeeDecorator implements Coffee {
    protected Coffee coffee;
    
    public CoffeeDecorator(Coffee coffee) {
        this.coffee = coffee;
    }
    
    @Override
    public String getDescription() {
        return coffee.getDescription();
    }
    
    @Override
    public double getCost() {
        return coffee.getCost();
    }
}

4. 具体装饰器(ConcreteDecorator)

java 复制代码
public class MilkDecorator extends CoffeeDecorator {
    public MilkDecorator(Coffee coffee) {
        super(coffee);
    }
    
    @Override
    public String getDescription() {
        return coffee.getDescription() + ", Milk";
    }
    
    @Override
    public double getCost() {
        return coffee.getCost() + 0.5;
    }
}

public class SugarDecorator extends CoffeeDecorator {
    public SugarDecorator(Coffee coffee) {
        super(coffee);
    }
    
    @Override
    public String getDescription() {
        return coffee.getDescription() + ", Sugar";
    }
    
    @Override
    public double getCost() {
        return coffee.getCost() + 0.2;
    }
}

public class WhipDecorator extends CoffeeDecorator {
    public WhipDecorator(Coffee coffee) {
        super(coffee);
    }
    
    @Override
    public String getDescription() {
        return coffee.getDescription() + ", Whip";
    }
    
    @Override
    public double getCost() {
        return coffee.getCost() + 0.7;
    }
}

使用示例

java 复制代码
public class CoffeeShop {
    public static void main(String[] args) {
        // 基础咖啡
        Coffee coffee = new SimpleCoffee();
        System.out.println("Cost: " + coffee.getCost() + ", Description: " + coffee.getDescription());
        
        // 添加牛奶
        Coffee milkCoffee = new MilkDecorator(coffee);
        System.out.println("Cost: " + milkCoffee.getCost() + ", Description: " + milkCoffee.getDescription());
        
        // 添加糖
        Coffee sweetMilkCoffee = new SugarDecorator(milkCoffee);
        System.out.println("Cost: " + sweetMilkCoffee.getCost() + ", Description: " + sweetMilkCoffee.getDescription());
        
        // 添加奶油
        Coffee whippedSweetMilkCoffee = new WhipDecorator(sweetMilkCoffee);
        System.out.println("Cost: " + whippedSweetMilkCoffee.getCost() + ", Description: " + whippedSweetMilkCoffee.getDescription());
        
        // 直接创建复杂组合
        Coffee complexCoffee = new WhipDecorator(
            new SugarDecorator(
                new MilkDecorator(
                    new SimpleCoffee()
                )
            )
        );
        System.out.println("Complex Coffee - Cost: " + complexCoffee.getCost() + ", Description: " + complexCoffee.getDescription());
    }
}

输出结果

复制代码
Cost: 2.0, Description: Simple Coffee
Cost: 2.5, Description: Simple Coffee, Milk
Cost: 2.7, Description: Simple Coffee, Milk, Sugar
Cost: 3.4, Description: Simple Coffee, Milk, Sugar, Whip
Complex Coffee - Cost: 3.4, Description: Simple Coffee, Milk, Sugar, Whip

实际应用场景

1. Java IO流

java 复制代码
// 基础流
InputStream fileStream = new FileInputStream("file.txt");

// 装饰器:缓冲流
InputStream bufferedStream = new BufferedInputStream(fileStream);

// 装饰器:数据流
DataInputStream dataStream = new DataInputStream(bufferedStream);

// 装饰器:压缩流
GZIPInputStream compressedStream = new GZIPInputStream(dataStream);

2. 图形界面组件

复制代码
public interface Window {
    void draw();
    String getDescription();
}

public class SimpleWindow implements Window {
    @Override
    public void draw() {
        System.out.println("绘制基础窗口");
    }
    
    @Override
    public String getDescription() {
        return "基础窗口";
    }
}

public abstract class WindowDecorator implements Window {
    protected Window decoratedWindow;
    
    public WindowDecorator(Window window) {
        this.decoratedWindow = window;
    }
    
    @Override
    public void draw() {
        decoratedWindow.draw();
    }
    
    @Override
    public String getDescription() {
        return decoratedWindow.getDescription();
    }
}

public class ScrollBarDecorator extends WindowDecorator {
    public ScrollBarDecorator(Window window) {
        super(window);
    }
    
    @Override
    public void draw() {
        decoratedWindow.draw();
        drawScrollBar();
    }
    
    private void drawScrollBar() {
        System.out.println("绘制滚动条");
    }
    
    @Override
    public String getDescription() {
        return decoratedWindow.getDescription() + "(带滚动条)";
    }
}

public class BorderDecorator extends WindowDecorator {
    public BorderDecorator(Window window) {
        super(window);
    }
    
    @Override
    public void draw() {
        decoratedWindow.draw();
        drawBorder();
    }
    
    private void drawBorder() {
        System.out.println("绘制边框");
    }
    
    @Override
    public String getDescription() {
        return decoratedWindow.getDescription() + "(带边框)";
    }
}

装饰器模式的优势

  1. 灵活性:可以在运行时动态添加或移除功能
  2. 开闭原则:对扩展开放,对修改关闭
  3. 单一职责:每个装饰器只负责一个功能
  4. 组合性:可以任意组合多个装饰器
  5. 透明性:客户端代码不需要知道装饰器的存在

适用场景

  1. 动态功能扩展:需要在运行时添加功能
  2. 避免子类爆炸:当继承会导致大量子类时
  3. 功能组合:需要灵活组合多个功能
  4. 现有代码扩展:不想修改现有代码结构
  5. 责任分离:将不同功能分离到不同装饰器中

与其他模式的区别

  • 适配器模式:改变接口,装饰器保持接口不变
  • 代理模式:控制访问,装饰器扩展功能
  • 组合模式:处理树形结构,装饰器处理链式结构
  • 策略模式:替换算法,装饰器添加功能

注意事项

  • 过度使用:可能导致大量小类
  • 调试困难:多层装饰可能难以调试
  • 性能影响:多层装饰可能影响性能
  • 设计复杂性:需要仔细设计装饰器层次

最佳实践

  • 保持简单:避免创建过于复杂的装饰器层次
  • 文档化:清楚记录装饰器的功能和使用方式
  • 测试:充分测试装饰器的组合效果
  • 命名规范:使用清晰的命名约定

装饰器模式是Java中非常实用的设计模式,特别适合需要动态扩展功能的场景,如Java IO流、图形界面组件等。它提供了一种灵活而强大的方式来扩展对象功能,是现代软件开发中不可或缺的设计模式之一。

下一篇: 装饰器模式和建造者模式的使用场景和区别-CSDN博客