结构型:装饰器模式
目录
1、核心思想
2、实现方式
2.1 模式结构
2.2 实现案例
3、优缺点分析
4、适用场景
1、核心思想
目的:在不改变其原始结构的前提下使客体功能得到扩展、增强。
核心:组合替代继承
举例:
1> 化妆:通过对素颜的人,进行顺序不确定的各种步骤(粉底、口红、睫毛膏等)的化妆,从而达到想要的结果
2> “java.io”包里一系列的流处理类InputStream、FileInputStream、BufferedInputStream、ZipInputStream等
File file = new File("/压缩包.zip");
//开始装饰
ZipInputStream zipInputStream = new ZipInputStream(new BufferedInputStream(new FileInputStream(file))
)
首先以文件file初始化并构造文件输入流FileInputStream,然后外层用缓冲输入流BufferedInputStream进行装饰,使文件输入流具备内存缓冲的功能,最外层再用压缩包输入流ZipInputStream进行最终装饰,使文件输入流具备Zip格式文件的功能,之后我们就可以对压缩包进行解压操作了
3> GUI组件:为按钮添加边框、滚动条等动态效果
4> Web中间件:请求处理链中的身份验证、日志记录、压缩等装饰逻辑
2、实现方式
2.1 模式结构
四个核心角色:
- Component(组件接口):所有被装饰组件及装饰器对应的接口标准,指定进行装饰的行为方法。
- ConcreteComponent(组件实现):被装饰组件,实现组件接口,是被装饰的原始对象。
- Decorator(装饰器):装饰器的高层抽象类,同样实现组件接口标准,且包含一个被装饰的组件。
- ConcreteDecorator(装饰器实现):继承自装饰器抽象类的具体子类装饰器,可以有多种实现,在被装饰组件对象的基础上为其添加新的特性。
2.2 实现案例
咖啡店提供基础咖啡(如美式咖啡),并支持动态添加牛奶、糖等配料,价格和描述需随配料叠加。
// 1、组件接口
interface Coffee {double getCost();String getDescription();
}// 2、具体组件:基础咖啡
class SimpleCoffee implements Coffee {@Overridepublic double getCost() { return 2.0; }@Overridepublic String getDescription() { return "美式咖啡"; }
}// 3、装饰器基类
abstract class CoffeeDecorator implements Coffee {protected Coffee decoratedCoffee;//被装饰组件变量(基础组件)public CoffeeDecorator(Coffee coffee) { this.decoratedCoffee = coffee; }
}// 4、具体装饰器:加牛奶
class MilkDecorator extends CoffeeDecorator {public MilkDecorator(Coffee coffee) { super(coffee); }@Overridepublic double getCost() {return decoratedCoffee.getCost() + 0.5; // 叠加牛奶价格}@Overridepublic String getDescription() {return decoratedCoffee.getDescription() + " + 牛奶"; // 叠加描述}
}// 具体装饰器:加糖
class SugarDecorator extends CoffeeDecorator {public SugarDecorator(Coffee coffee) { super(coffee); }@Overridepublic double getCost() {return decoratedCoffee.getCost() + 0.2;}@Overridepublic String getDescription() {return decoratedCoffee.getDescription() + " + 糖";}
}// 客户端调用
public class Client {public static void main(String[] args) {Coffee coffee = new SimpleCoffee();coffee = new MilkDecorator(coffee); // 动态装饰coffee = new SugarDecorator(coffee);System.out.println("订单: " + coffee.getDescription());System.out.println("总价: $" + coffee.getCost());}
}
输出:
订单: 美式咖啡 + 牛奶 + 糖
总价: $2.7
3、优缺点分析
优点:
动态扩展功能:无需修改原有代码,通过嵌套装饰器灵活组合功能。
避免类爆炸:替代多层次的继承结构(如
CoffeeWithMilkAndSugar
、CoffeeWithMilk
等子类)。单一职责原则:每个装饰器仅关注一个功能点。
开闭原则:支持扩展新装饰器,且不修改现有代码。
缺点:
复杂度增加:多层装饰可能导致对象链难以跟踪和调试。
冗余代码:需为每个装饰器实现组件接口的所有方法(即使仅增强部分逻辑)。
初始化繁琐:创建对象时需逐层包装装饰器。
4、适用场景
-
动态功能扩展:
-
为对象添加日志、缓存、权限校验等非核心功能。
-
如Java I/O流(
BufferedInputStream
装饰FileInputStream
)。
-
-
不可继承的场景:
-
当目标类被
final
修饰,或已有复杂的继承层次时。
-
-
撤销功能需求:
-
通过移除装饰器回退到原始状态(需自行管理装饰链)。
-