一、概述
装饰模式(Decorator Pattern)
是一种结构型设计模式,它允许在不改变对象接口的前提下向对象添加新的行为。通过使用装饰模式,我们可以动态地将责任附加到对象上,而无需修改代码中的其他类。
二、使用场景
- 需要扩展一个类的功能,或给一个类添加附加职责。
- 动态地为一个对象添加功能,这些功能可以随时撤销。
- 通过一种方式将类的核心职责和装饰功能区分开来,以便简化代码和减少重复代码。
三、结构
装饰模式主要包含以下几个部分:
- 组件接口(Component):定义了要动态添加功能的对象的接口。
- 具体组件(ConcreteComponent):实现了组件接口的类。
- 装饰类(Decorator):持有一个组件对象的引用,并实现组件接口,通过这种方式,装饰类可以在调用具体组件的方法前后添加新的行为。
- 具体装饰类(ConcreteDecorator):继承装饰类,并具体实现装饰功能。
四、代码实现
下面是一个Java实现装饰模式的例子,展示了如何给一个简单的文本消息添加多种装饰(如加密和压缩)。
// Component 接口
interface Message {
String getContent();
}
// 具体组件
class TextMessage implements Message {
private String content;
public TextMessage(String content) {
this.content = content;
}
@Override
public String getContent() {
return content;
}
}
// 装饰类
abstract class MessageDecorator implements Message {
protected Message message;
public MessageDecorator(Message message) {
this.message = message;
}
@Override
public String getContent() {
return message.getContent();
}
}
// 具体装饰类 A
class EncryptedMessage extends MessageDecorator {
public EncryptedMessage(Message message) {
super(message);
}
@Override
public String getContent() {
return encrypt(message.getContent());
}
private String encrypt(String content) {
// 简单的加密逻辑
return new StringBuilder(content).reverse().toString();
}
}
// 具体装饰类 B
class CompressedMessage extends MessageDecorator {
public CompressedMessage(Message message) {
super(message);
}
@Override
public String getContent() {
return compress(message.getContent());
}
private String compress(String content) {
// 简单的压缩逻辑
return content.substring(0, 5); // 仅为示例
}
}
// 客户端代码
public class DecoratorPatternDemo {
public static void main(String[] args) {
Message message = new TextMessage("Hello, World!");
// 加密消息
Message encryptedMessage = new EncryptedMessage(message);
System.out.println("Encrypted: " + encryptedMessage.getContent());
// 压缩消息
Message compressedMessage = new CompressedMessage(message);
System.out.println("Compressed: " + compressedMessage.getContent());
// 先加密再压缩
Message encryptedCompressedMessage = new CompressedMessage(new EncryptedMessage(message));
System.out.println("Encrypted & Compressed: " + encryptedCompressedMessage.getContent());
}
}
五、装饰模式在JDK中的运用
1. java.io
包中的类
java.io
包中的类是装饰模式的经典实现之一。特别是 InputStream
、OutputStream
、Reader
和 Writer
等类,这些类的装饰器实现方式使得可以动态地向基本流添加功能。
示例代码:
import java.io.*;
public class DecoratorPatternInJDK {
public static void main(String[] args) {
try {
InputStream fileStream = new FileInputStream("example.txt");
InputStream bufferedStream = new BufferedInputStream(fileStream);
InputStream gzipStream = new GZIPInputStream(bufferedStream);
int data;
while ((data = gzipStream.read()) != -1) {
System.out.print((char) data);
}
gzipStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
在这个例子中,FileInputStream
是一个基本的输入流,BufferedInputStream
和 GZIPInputStream
是装饰器类,它们为输入流添加了缓冲和解压缩的功能。
2. java.util
包中的 Collections
类
Collections
类提供了一些静态方法来返回集合的包装器,这些包装器为集合添加了同步(线程安全)和不可变的特性。
示例代码:
import java.util.*;
public class CollectionsDecoratorExample {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("One");
list.add("Two");
list.add("Three");
List<String> synchronizedList = Collections.synchronizedList(list);
List<String> unmodifiableList = Collections.unmodifiableList(list);
// 输出原始列表
System.out.println("Original List: " + list);
// 输出同步列表
System.out.println("Synchronized List: " + synchronizedList);
// 输出不可修改列表
System.out.println("Unmodifiable List: " + unmodifiableList);
// 尝试修改不可修改列表将引发 UnsupportedOperationException
try {
unmodifiableList.add("Four");
} catch (UnsupportedOperationException e) {
System.out.println("Cannot modify unmodifiable list");
}
}
}
在这个例子中,synchronizedList
和 unmodifiableList
是对原始列表的装饰器,为其添加了同步和不可变的特性。
六、结论
装饰模式通过将附加功能包装在装饰类中,使得我们可以灵活地扩展对象的功能,而不需要修改对象的核心代码。这种模式在需要扩展类的功能时特别有用,特别是当扩展功能是可以动态组合和变化的。