装饰器模式 (Decorator Pattern)
动态地给一个对象添加一些额外的职责
模式定义
装饰器模式是一种结构型设计模式,它允许动态地给一个对象添加一些额外的职责,就增加功能来说,装饰器模式相比生成子类更为灵活。装饰器模式通过创建一个包装对象来包裹真实的对象。
模式结构
graph TD
A[Client] --> B((Component))
B --> C[ConcreteComponent]
B --> D[Decorator]
D --> E[ConcreteDecorator]
实现方式
基础实现
定义组件接口,实现具体组件和装饰器类。
// 组件接口
public interface Coffee {
double getCost();
String getDescription();
}
// 具体组件 - 简单咖啡
public class SimpleCoffee implements Coffee {
@Override
public double getCost() {
return 2.0;
}
@Override
public String getDescription() {
return "简单咖啡";
}
}
// 装饰器抽象类
public abstract class CoffeeDecorator implements Coffee {
protected Coffee coffee;
public CoffeeDecorator(Coffee coffee) {
this.coffee = coffee;
}
@Override
public double getCost() {
return coffee.getCost();
}
@Override
public String getDescription() {
return coffee.getDescription();
}
}
// 具体装饰器 - 牛奶
public class Milk extends CoffeeDecorator {
public Milk(Coffee coffee) {
super(coffee);
}
@Override
public double getCost() {
return super.getCost() + 0.5;
}
@Override
public String getDescription() {
return super.getDescription() + ", 牛奶";
}
}
// 具体装饰器 - 糖
public class Sugar extends CoffeeDecorator {
public Sugar(Coffee coffee) {
super(coffee);
}
@Override
public double getCost() {
return super.getCost() + 0.3;
}
@Override
public String getDescription() {
return super.getDescription() + ", 糖";
}
}
// 具体装饰器 - 奶油
public class Whip extends CoffeeDecorator {
public Whip(Coffee coffee) {
super(coffee);
}
@Override
public double getCost() {
return super.getCost() + 0.7;
}
@Override
public String getDescription() {
return super.getDescription() + ", 奶油";
}
}
使用示例
public class CoffeeShop {
public static void main(String[] args) {
// 简单咖啡
Coffee coffee = new SimpleCoffee();
System.out.println("描述: " + coffee.getDescription());
System.out.println("价格: $" + coffee.getCost());
// 加牛奶的咖啡
coffee = new Milk(coffee);
System.out.println("描述: " + coffee.getDescription());
System.out.println("价格: $" + coffee.getCost());
// 加糖的咖啡
coffee = new Sugar(coffee);
System.out.println("描述: " + coffee.getDescription());
System.out.println("价格: $" + coffee.getCost());
// 加奶油的咖啡
coffee = new Whip(coffee);
System.out.println("描述: " + coffee.getDescription());
System.out.println("价格: $" + coffee.getCost());
// 创建复杂的咖啡
Coffee specialCoffee = new Whip(new Sugar(new Milk(new SimpleCoffee())));
System.out.println("\n特制咖啡:");
System.out.println("描述: " + specialCoffee.getDescription());
System.out.println("价格: $" + specialCoffee.getCost());
}
}
文本处理示例
使用装饰器模式处理文本格式化。
// 文本组件接口
public interface Text {
String getContent();
}
// 具体文本组件
public class PlainText implements Text {
private String content;
public PlainText(String content) {
this.content = content;
}
@Override
public String getContent() {
return content;
}
}
// 文本装饰器抽象类
public abstract class TextDecorator implements Text {
protected Text text;
public TextDecorator(Text text) {
this.text = text;
}
@Override
public String getContent() {
return text.getContent();
}
}
// 具体装饰器 - 粗体
public class BoldText extends TextDecorator {
public BoldText(Text text) {
super(text);
}
@Override
public String getContent() {
return "" + super.getContent() + "";
}
}
// 具体装饰器 - 斜体
public class ItalicText extends TextDecorator {
public ItalicText(Text text) {
super(text);
}
@Override
public String getContent() {
return "" + super.getContent() + "";
}
}
// 具体装饰器 - 下划线
public class UnderlineText extends TextDecorator {
public UnderlineText(Text text) {
super(text);
}
@Override
public String getContent() {
return "" + super.getContent() + "";
}
}
// 客户端使用
public class TextEditor {
public static void main(String[] args) {
Text text = new PlainText("Hello World");
System.out.println("原文: " + text.getContent());
// 添加粗体
text = new BoldText(text);
System.out.println("粗体: " + text.getContent());
// 添加斜体
text = new ItalicText(text);
System.out.println("粗体+斜体: " + text.getContent());
// 添加下划线
text = new UnderlineText(text);
System.out.println("粗体+斜体+下划线: " + text.getContent());
// 创建复杂格式
Text complexText = new UnderlineText(new ItalicText(new BoldText(new PlainText("装饰器模式"))));
System.out.println("\n复杂格式: " + complexText.getContent());
}
}
经典案例
Java I/O 流
Java I/O 流库是装饰器模式的经典应用。
// Java I/O 流中的装饰器模式示例
import java.io.*;
public class IOStreamExample {
public static void main(String[] args) {
try {
// FileInputStream 是具体组件
FileInputStream fis = new FileInputStream("input.txt");
// BufferedInputStream 是装饰器,添加缓冲功能
BufferedInputStream bis = new BufferedInputStream(fis);
// DataInputStream 是装饰器,添加读取基本数据类型的功能
DataInputStream dis = new DataInputStream(bis);
// 可以继续添加更多装饰器
// 例如LineNumberInputStream(已废弃)可以添加行号功能
// 读取数据
int data = dis.read();
while (data != -1) {
System.out.print((char) data);
data = dis.read();
}
dis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
// 类结构说明:
// InputStream (Component)
// FileInputStream, ByteArrayInputStream (ConcreteComponent)
// FilterInputStream (Decorator)
// BufferedInputStream, DataInputStream (ConcreteDecorator)
Swing GUI 组件
Swing 中的 GUI 组件也使用了装饰器模式。
// Swing 中的装饰器模式示例
import javax.swing.*;
import java.awt.*;
public class SwingDecoratorExample {
public static void main(String[] args) {
JFrame frame = new JFrame("装饰器模式示例");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 300);
// JLabel 是具体组件
JLabel label = new JLabel("Hello World");
// 可以通过设置属性来"装饰"组件
label.setFont(new Font("Arial", Font.BOLD, 16));
label.setForeground(Color.BLUE);
label.setBorder(BorderFactory.createEtchedBorder());
// JPanel 是容器组件
JPanel panel = new JPanel();
panel.add(label);
frame.add(panel);
frame.setVisible(true);
}
}
// 更复杂的装饰示例
import javax.swing.border.*;
import java.awt.*;
public class ComplexSwingDecorator {
public static void main(String[] args) {
JFrame frame = new JFrame("复杂装饰示例");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 300);
JButton button = new JButton("点击我");
// 多层装饰
// 1. 设置字体
button.setFont(new Font("Arial", Font.BOLD, 14));
// 2. 设置背景和前景色
button.setBackground(Color.LIGHT_GRAY);
button.setForeground(Color.BLUE);
// 3. 添加边框装饰
Border innerBorder = BorderFactory.createLineBorder(Color.BLUE, 2);
Border outerBorder = BorderFactory.createEmptyBorder(10, 10, 10, 10);
button.setBorder(BorderFactory.createCompoundBorder(outerBorder, innerBorder));
frame.add(button);
frame.setVisible(true);
}
}
适用场景
- 动态地给对象添加功能
- 不修改原有代码
- 功能组合
- 当需要动态地给一个对象添加功能,而不影响其他对象时
- 当需要通过继承来扩展功能会导致子类数量急剧增加时
- 当需要将一系列功能进行组合,并且这些功能可以灵活搭配时
优缺点
优点
- 继承的替代方案:装饰器模式提供了一种比继承更灵活的替代方案,可以动态地扩展对象功能
- 符合开闭原则:装饰器模式符合开闭原则,可以在不修改现有代码的情况下扩展对象功能
- 功能组合灵活:可以通过不同的装饰器组合来实现不同的功能,非常灵活
- 比继承更灵活:避免了大量子类的产生
- 可以动态地扩展对象功能:可以在运行时添加或删除功能
缺点
- 产生很多小对象:使用装饰器模式会产生很多小对象,增加系统的复杂度
- 调试困难:由于装饰器模式会产生很多小对象,可能会增加调试的难度
- 多次装饰的对象需要多次包装:多次装饰的对象需要逐级包装,可能会降低性能
- 容易出错:使用装饰器模式时容易出错,对于多次装饰的对象,调试时寻找错误可能比较困难