装饰者模式(Decorator Pattern)学习笔记
1. 模式定义
结构型设计模式,动态地为对象添加额外的职责。通过组合而非继承的方式扩展功能,提供比继承更机动的更换方案。
2. 适用场景
✅ 需要动态/透明地给对象添加功能
✅ 需要撤销附加功能时
✅ 无法通过继承扩展功能(final类)
✅ 需要组合多个可选功能
✅ 克制"子类爆炸"问题
3. 模式结构
4. 核心脚色
脚色说明Component抽象组件,定义被装饰对象的接口ConcreteComponent详细组件,实现基本功能Decorator装饰者抽象类,持有组件引用并实现组件接口ConcreteDecorator详细装饰者,添加额外功能 5. 代码示例
5.1 咖啡加料示例
- // 抽象组件
- public interface Coffee {
- double getCost();
- String getDescription();
- }
- // 具体组件
- public class SimpleCoffee implements Coffee {
- public double getCost() {
- return 2.0;
- }
-
- public String getDescription() {
- return "咖啡";
- }
- }
- // 抽象装饰者
- public abstract class CoffeeDecorator implements Coffee {
- protected Coffee decoratedCoffee;
-
- public CoffeeDecorator(Coffee coffee) {
- this.decoratedCoffee = coffee;
- }
-
- public double getCost() {
- return decoratedCoffee.getCost();
- }
-
- public String getDescription() {
- return decoratedCoffee.getDescription();
- }
- }
- // 具体装饰者
- public class MilkDecorator extends CoffeeDecorator {
- public MilkDecorator(Coffee coffee) {
- super(coffee);
- }
-
- public double getCost() {
- return super.getCost() + 0.5;
- }
-
- public String getDescription() {
- return super.getDescription() + " + 牛奶";
- }
- }
- public class SugarDecorator extends CoffeeDecorator {
- public SugarDecorator(Coffee coffee) {
- super(coffee);
- }
-
- public double getCost() {
- return super.getCost() + 0.2;
- }
-
- public String getDescription() {
- return super.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.getCost());
- System.out.println("描述: " + coffee.getDescription());
- /* 输出:
- 总价: $2.7
- 描述: 咖啡 + 牛奶 + 糖 */
- }
- }
复制代码 6. 模式变种
- 透明装饰模式:保持接口完全一致,客户端无需知道装饰存在
- 半透明装饰模式:新增装饰者特有方法,客户端需要知道详细装饰范例
- 组合装饰器:通过链式调用实现多层装饰
- Coffee coffee = new SugarDecorator(new MilkDecorator(new SimpleCoffee()));
复制代码 7. 优缺点分析
✔️ 优点:
- 扩展性比继承更好
- 动态添加/撤销功能
- 克制继承导致的类爆炸
- 符合开闭原则
❌ 缺点:
- 产生大量小对象
- 多层装饰增加调试难度
- 装饰次序大概影响结果
- 需要管理装饰器组合关系
8. 相干模式对比
模式目的关键区别适配器模式接口转换改变对象接口代理模式控制访问保持接口相同组合模式树形结构处理装饰者是被组合对象的包装责任链模式哀求传递装饰者可以停止处理过程 9. 实际应用案例
- Java IO流体系:
- new BufferedInputStream(new FileInputStream("file.txt"));
复制代码 - Spring Security的过滤器链
- Java GUI的组件装饰(Border/Scrollbar)
- Servlet API的HttpServletRequestWrapper
- Spring Web的HandlerInterceptor
- MyBatis的Cache装饰器(FifoCache/LruCache)
10. 最佳实践建议
- 保持装饰接口透明:尽量不添加新方法,保持与组件接口一致
- 控制装饰层级:克制超过3层嵌套装饰
- 优先使用组合:通过组合差别装饰器实现功能叠加
- 注意装饰次序:明白装饰器的应用次序规则
- 使用工厂方法:封装复杂装饰组合的创建过程
- 实现撤销机制:提供removeDecorator()方法支持功能撤销
11. 扩展应用(增强HttpServletRequest)
- public class LoggingHttpRequest extends HttpServletRequestWrapper {
- public LoggingHttpRequest(HttpServletRequest request) {
- super(request);
- }
-
- @Override
- public String getParameter(String name) {
- String value = super.getParameter(name);
- System.out.println("获取参数: " + name + "=" + value);
- return value;
- }
-
- @Override
- public Part getPart(String name) throws IOException, ServletException {
- Part part = super.getPart(name);
- System.out.println("上传文件: " + name + " size=" + part.getSize());
- return part;
- }
- }
- // 在Filter中使用
- public class LoggingFilter implements Filter {
- public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
- throws IOException, ServletException {
- HttpServletRequest wrappedRequest = new LoggingHttpRequest((HttpServletRequest) request);
- chain.doFilter(wrappedRequest, response);
- }
- }
复制代码 |