正统三国冰狐手游
1.19GB · 2025-12-10
在软件开发中,我们常常会遇到一个问题:如何给一个对象动态地添加新功能,同时又不想修改它的代码?如果直接在原有类上修修补补,代码会变得臃肿复杂,难以维护。
今天,我们就来聊一个能完美解决这个问题的设计模式——装饰器模式 (Decorator Pattern) 。
简单来说,装饰器模式允许你在不改变一个对象原有代码的前提下,为它增加新的职责或功能。 它就像是给一个基础对象“穿上”不同的“配件”,每件“配件”都代表一个新功能。
为了更好地理解这个模式,我们来想象一下在咖啡店点咖啡的场景。
这个模式的关键在于,无论是黑咖啡还是牛奶、糖,它们都遵循同一个接口(Interface) 。这个接口定义了所有饮料都必须具备的行为,比如 getDescription()(获取描述)和 cost()(获取价格)。
BlackCoffee 类的代码。如果未来想增加新的配料,比如“奶油”,我们只需要新增一个 CreamDecorator 类即可,对原有代码完全无侵入。MilkCoffee、SugarCoffee、MilkSugarCoffee 等大量子类来应对不同的组合。这会让代码变得异常复杂。装饰器模式通过组合而非继承的方式,巧妙地解决了这个问题。为了更直观地理解,我们来看一下装饰器模式的 UML 类图。
Beverage:定义了所有对象都必须实现的接口。BlackCoffee:具体组件,提供了最基础的功能。BeverageDecorator:抽象装饰器,继承了接口并持有一个接口的引用。MilkDecorator 和 SugarDecorator:具体的装饰器,用来添加新功能。除了我们自己手写的代码,装饰器模式在许多成熟的框架中都有广泛应用。
Java 的 I/O 流库是装饰器模式最经典的例子之一。InputStream 和 OutputStream 是最基础的接口。而像 BufferedInputStream、DataInputStream、GZIPInputStream 等类,都是装饰器。它们通过包裹一个基础的 InputStream,为其添加新的功能,比如提供缓冲、处理基本数据类型、文件解压缩等。
在 Spring 框架中,装饰器模式与代理模式的思想常常结合使用。当一个 Bean 被 Spring AOP 增强时,Spring 会创建一个代理对象。这个代理对象实际上就是装饰器,它包裹着原始的 Bean 对象。当方法被调用时,代理对象会先执行一些额外的逻辑(比如事务的开启和提交、日志的记录),然后再将调用转发给原始的 Bean 对象。这种设计使得 Spring 可以在不修改原始业务代码的情况下,为其动态地添加横切关注点(Cross-cutting Concerns),完美体现了装饰器模式的精髓。
最后,为了更精确地理解装饰器模式,我们来把它和两个容易混淆的模式进行比较。
接下来,我们用 Java 来实现这个咖啡店的例子。
首先,定义所有饮料都必须实现的接口。
// Beverage.java
public interface Beverage {
String getDescription();
double cost();
}
然后,我们创建最基础的饮料类,它实现了 Beverage 接口。
// BlackCoffee.java
public class BlackCoffee implements Beverage {
@Override
public String getDescription() {
return "黑咖啡";
}
@Override
public double cost() {
return 5.0;
}
}
为了让所有装饰器都具有统一的结构,我们创建一个抽象装饰器类。它也实现了 Beverage 接口,并持有一个对 Beverage 对象的引用。所有的具体装饰器都将继承这个抽象类。
// BeverageDecorator.java
public abstract class BeverageDecorator implements Beverage {
protected Beverage beverage;
public BeverageDecorator(Beverage beverage) {
this.beverage = beverage;
}
@Override
public abstract String getDescription();
@Override
public abstract double cost();
}
现在,我们创建具体的装饰器类。它们继承 BeverageDecorator 并重写方法,在原有功能上添加新的职责。
// MilkDecorator.java
public class MilkDecorator extends BeverageDecorator {
public MilkDecorator(Beverage beverage) {
super(beverage);
}
@Override
public String getDescription() {
// 在原有描述上添加 "加奶"
return beverage.getDescription() + ",加奶";
}
@Override
public double cost() {
// 在原有价格上加上牛奶的费用
return beverage.cost() + 3.0;
}
}
// SugarDecorator.java
public class SugarDecorator extends BeverageDecorator {
public SugarDecorator(Beverage beverage) {
super(beverage);
}
@Override
public String getDescription() {
// 在原有描述上添加 "加糖"
return beverage.getDescription() + ",加糖";
}
@Override
public double cost() {
// 在原有价格上加上糖的费用
return beverage.cost() + 1.0;
}
}
最后,我们来看看如何将这些组件组合起来,构造出我们想要的咖啡。
// Main.java
public class Main {
public static void main(String[] args) {
// 1. 来一杯纯黑咖啡
Beverage blackCoffee = new BlackCoffee();
System.out.println("描述: " + blackCoffee.getDescription() + ",价格: " + blackCoffee.cost());
// 2. 来一杯加奶的黑咖啡
Beverage milkCoffee = new MilkDecorator(blackCoffee);
System.out.println("描述: " + milkCoffee.getDescription() + ",价格: " + milkCoffee.cost());
// 3. 来一杯加奶又加糖的黑咖啡
Beverage milkSugarCoffee = new SugarDecorator(milkCoffee);
System.out.println("描述: " + milkSugarCoffee.getDescription() + ",价格: " + milkSugarCoffee.cost());
}
}
运行结果:
描述: 黑咖啡,价格: 5.0
描述: 黑咖啡,加奶,价格: 8.0
描述: 黑咖啡,加奶,加糖,价格: 9.0
装饰器模式是一种强大且灵活的设计模式。它通过“包裹”而非修改的方式,让我们可以像搭乐高积木一样,动态地为对象添加和组合功能。当你的系统需要灵活扩展、避免大量子类时,不妨考虑一下这个精妙的模式。