装饰者模式基础概念
装饰者模式是一种结构型设计模式,其核心思想是动态地将责任附加到对象上,从而实现对对象功能的扩展。与继承相比,装饰者模式提供了更灵活的替代方案,它通过组合的方式在运行时为对象添加新功能,而无需修改其原有结构。
装饰者模式的核心组件
- 抽象组件 (Component) - 定义对象的接口,可以是抽象类或接口
- 具体组件 (ConcreteComponent) - 实现抽象组件接口,是被装饰的原始对象
- 抽象装饰者 (Decorator) - 实现抽象组件接口,并持有一个抽象组件的引用
- 具体装饰者 (ConcreteDecorator) - 继承抽象装饰者,负责为具体组件添加额外功能
装饰者模式的实现
下面通过一个咖啡饮品的例子展示装饰者模式的实现:
// 抽象组件 - 饮品
interface Beverage {
String getDescription();
double cost();
}
// 具体组件 - 浓缩咖啡
class Espresso implements Beverage {
@Override
public String getDescription() {
return "Espresso";
}
@Override
public double cost() {
return 1.99;
}
}
// 具体组件 - 黑咖啡
class DarkRoast implements Beverage {
@Override
public String getDescription() {
return "Dark Roast Coffee";
}
@Override
public double cost() {
return 1.59;
}
}
// 抽象装饰者 - 调料
abstract class CondimentDecorator implements Beverage {
protected Beverage beverage; // 持有被装饰对象的引用
public CondimentDecorator(Beverage beverage) {
this.beverage = beverage;
}
@Override
public String getDescription() {
return beverage.getDescription();
}
@Override
public double cost() {
return beverage.cost();
}
}
// 具体装饰者 - 牛奶
class Milk extends CondimentDecorator {
public Milk(Beverage beverage) {
super(beverage);
}
@Override
public String getDescription() {
return beverage.getDescription() + ", Milk";
}
@Override
public double cost() {
return beverage.cost() + 0.3;
}
}
// 具体装饰者 - 摩卡
class Mocha extends CondimentDecorator {
public Mocha(Beverage beverage) {
super(beverage);
}
@Override
public String getDescription() {
return beverage.getDescription() + ", Mocha";
}
@Override
public double cost() {
return beverage.cost() + 0.4;
}
}
// 具体装饰者 - 豆浆
class Soy extends CondimentDecorator {
public Soy(Beverage beverage) {
super(beverage);
}
@Override
public String getDescription() {
return beverage.getDescription() + ", Soy";
}
@Override
public double cost() {
return beverage.cost() + 0.25;
}
}
// 客户端代码
public class DecoratorPatternClient {
public static void main(String[] args) {
// 创建一个纯浓缩咖啡
Beverage beverage1 = new Espresso();
System.out.println(beverage1.getDescription() + " $" + beverage1.cost());
// 创建一个加双份摩卡和牛奶的黑咖啡
Beverage beverage2 = new DarkRoast();
beverage2 = new Mocha(beverage2); // 加一份摩卡
beverage2 = new Mocha(beverage2); // 加第二份摩卡
beverage2 = new Milk(beverage2); // 加牛奶
System.out.println(beverage2.getDescription() + " $" + beverage2.cost());
// 创建一个加豆浆和摩卡的浓缩咖啡
Beverage beverage3 = new Espresso();
beverage3 = new Soy(beverage3); // 加豆浆
beverage3 = new Mocha(beverage3); // 加摩卡
System.out.println(beverage3.getDescription() + " $" + beverage3.cost());
}
}
装饰者模式在 Java 标准库中的应用
装饰者模式在 Java 标准库中有广泛应用,例如:
- Java I/O 流 -
InputStream
、OutputStream
、Reader
和Writer
类使用装饰者模式
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
public class IOExample {
public static void main(String[] args) throws IOException {
// 创建一个文件输入流,并装饰为缓冲流
InputStream inputStream = new FileInputStream("example.txt");
inputStream = new BufferedInputStream(inputStream);
// 读取数据
int data;
while ((data = inputStream.read()) != -1) {
// 处理数据
}
inputStream.close();
}
}
- Java 集合框架 -
Collections
类中的synchronizedXXX()
方法
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class CollectionsExample {
public static void main(String[] args) {
// 创建一个普通列表
List<String> list = new ArrayList<>();
// 使用装饰者模式将其转换为线程安全的列表
List<String> synchronizedList = Collections.synchronizedList(list);
}
}
装饰者模式的应用场景
- 动态添加功能 - 需要在运行时为对象动态添加功能,而不影响其他对象
- 功能组合 - 当需要通过组合多种功能来扩展对象时
- 替代继承 - 当使用继承会导致类爆炸(过多子类)时
- 透明增强 - 需要在不改变原有接口的情况下增强对象功能
装饰者模式的优缺点
优点:
- 灵活性高 - 可以在运行时动态添加或删除功能
- 符合开闭原则 - 无需修改原有代码,只需新增装饰者类
- 避免继承的复杂性 - 比继承更灵活,避免类层次结构的膨胀
- 可组合性强 - 可以通过组合多个装饰者实现复杂功能
缺点:
- 产生过多小对象 - 装饰者模式会产生大量的小对象,增加系统复杂度
- 调试困难 - 多层装饰会使代码调试和理解变得困难
- 依赖抽象 - 装饰者和被装饰者必须依赖于抽象接口
使用装饰者模式的注意事项
- 接口一致性 - 装饰者和被装饰者必须实现相同的接口
- 装饰顺序 - 装饰顺序可能影响最终结果,需要合理设计
- 避免过度装饰 - 过多的装饰层次会使代码难以理解和维护
- 基础组件的简单性 - 确保基础组件(ConcreteComponent)的设计简单,避免复杂逻辑
- 抽象装饰者的必要性 - 虽然可以直接实现具体装饰者,但使用抽象装饰者可以简化代码
装饰者模式是一种非常实用的设计模式,它通过组合而非继承的方式为对象提供了灵活的功能扩展能力。在实际开发中,装饰者模式常用于需要动态扩展对象功能的场景,如 Java I/O 流、GUI 组件等。