设计模式-装饰器模式

写在前面

Hello,我是易元,这篇文章是我学习设计模式时的笔记和心得体会。如果其中有错误,欢迎大家留言指正!

代码初期的快速实现

场景:互联网初创公司"极客海淘",团队只有3个成员(小易、产品小美、测试大哥老李),迎来了系统的第一次需求扩张(折扣),老板大手一挥:"先用起来再说!"

kotlin 复制代码
/** 
 * 订单逻辑处理器 
 */ 
public class OrderProcessor { 
    public double process(Double amount) { 
        System.out.println("计算订单金额:" + amount); 
        return amount; 
    } 
} 

/** 
 * 订单折扣处理器 
 */ 
public class DiscountOrderProcessor extends OrderProcessor { 
    private Double discount; 

    public DiscountOrderProcessor(Double discount) { 
        this.discount = discount; 
    } 

    public double process(Double amount) { 
        double process = super.process(amount); 
        System.out.println("订单折扣:" + discount); 
        System.out.println("商品折扣金额:" + (process * discount)); 
        return amount - process * discount; 
    } 
} 

团队日常
小易(叉腰):"搞定!"

紧急功能的应对方案

团队日常
产品小美(眨眼):"易哥,还能加个进口关税功能吗?客户提出的需求,而且催得紧~"
老李(摸鱼):"别慌,反正现在代码简单~"

订单关税处理器
kotlin 复制代码
public class TariffOrderProcessor extends OrderProcessor { 
    private Double tariff; 

    public TariffOrderProcessor(Double tariff) { 
        this.tariff = tariff; 
    } 

    public double process(Double amount) { 
        System.out.println("商品关税:" + tariff); 
        System.out.println("商品关税金额:" + amount * tariff); 
        return super.process(amount * tariff + amount); 
    } 
} 
订单关税 折扣 处理器
kotlin 复制代码
public class TariffDiscountOrderProcessor extends DiscountOrderProcessor { 
    private Double tariff; 

    public TariffDiscountOrderProcessor(Double tariff, Double discount) { 
        super(discount); 
        this.tariff = tariff; 
    } 

    public double process(Double amount) { 
        System.out.println("商品关税比例:" + tariff); 
        System.out.println("商品关税金额:" + (amount * tariff)); 
        return super.process(amount + amount * tariff); 
    } 
} 

设计缺陷显形

团队日常
产品小美(递咖啡):"易哥辛苦了,能再加赠品功能吗?客户说下次一定..."
小易(抓头发):"这继承树是要捅破天花板啊!"
老李(拍桌子):"测试用例要写疯了!这代码没法维护!"

累加功能存在的隐患

问题清单

  1. 类爆炸 :每加一个功能就继承一个子类,现在代码库里有TariffDiscountOrderProcessorOrderProcessorDiscountOrderProcessor...
  2. 功能耦合:进口订单和赠品功能写死在一起,无法单独存在
  3. 维护地狱:改个税率要改10个类!

引入设计模式重构

场景 :小易为了不被人说是屎山,偷偷学习了《设计模式之美》,决心用装饰器模式拯救订单系统。
设计模式选择 :装饰器模式(Decorator Pattern)
核心目标:优雅扩展,让产品经理的嘴不再开过山车

装饰器模式四要素
角色 职责 订单系统示例
Component 定义基础操作的接口 OrderDecorator
ConcreteComponent 基础实现类 OrderProcessorImpl
Decorator 持有组件引用并实现相同接口 OrderDecorator
ConcreteDecorator 添加具体功能的装饰器 DiscountDecorator

重构:装饰器模式实践

步骤1:定义组件接口(订单处理基类)
java 复制代码
public abstract class OrderDecorator implements OrderProcessor { 
    protected final OrderProcessor processor; 

    protected OrderDecorator(OrderProcessor processor) { 
        this.processor = processor; 
    } 

    @Override 
    public abstract double process(Double amount); 
} 
步骤2:实现基础组件(裸奔版处理器)
kotlin 复制代码
public class OrderProcessorImpl implements OrderProcessor { 
    @Override 
    public double process(Double amount) { 
        System.out.println("------------------订单基础处理------------------"); 
        System.out.println("计算订单金额:" + amount); 
        System.out.println("订单基础逻辑处理......."); 
        System.out.println("------------------------------------------------"); 
        return amount; 
    } 
} 
步骤3:创建装饰器基类(功能扩展骨架)
java 复制代码
public abstract class OrderDecorator implements OrderProcessor {

    protected final OrderProcessor processor;

    protected OrderDecorator(OrderProcessor processor) {
        this.processor = processor;
    }

    @Override
    public abstract double process(Double amount);
}
步骤4:实现具体装饰器(功能插件)
kotlin 复制代码
// 订单打折处理器类(具体装饰器)  
public class DiscountDecorator extends OrderDecorator { 
    private final Double discount; 

    protected DiscountDecorator(OrderProcessor processor, Double discount) { 
        super(processor); 
        this.discount = discount; 
    } 

    @Override 
    public double process(Double amount) { 
        System.out.println("------------------订单打折处理------------------"); 
        System.out.println("商品订单金额:" + amount); 
        System.out.println("订单折扣:" + discount); 
        System.out.println("商品折扣金额:" + (amount * discount)); 
        System.out.println("------------------------------------------------"); 
        return super.processor.process(amount * (1 - discount)); 
    } 
} 

// 订单关税处理器类(具体装饰器)  
public class TariffDiscountDecorator extends OrderDecorator { 
    private final Double tariff; 

    protected TariffDiscountDecorator(OrderProcessor processor, Double tariff) { 
        super(processor); 
        this.tariff = tariff; 
    } 

    @Override 
    public double process(Double amount) { 
        System.out.println("------------------订单关税处理------------------"); 
        System.out.println("商品订单金额:" + amount); 
        System.out.println("商品关税比例:" + tariff); 
        System.out.println("商品关税金额:" + (amount * tariff)); 
        System.out.println("------------------------------------------------"); 
        return super.processor.process(amount * (1 + tariff)); 
    } 
} 
测试代码
arduino 复制代码
public class OrderProcessorTest { 
    @Test 
    public void discountTest() { 
        OrderProcessor orderDecorator = new OrderProcessorImpl(); 

        // 促销增加 10% 折扣  
        orderDecorator = new DiscountDecorator(orderDecorator, 0.1); 

        // 增加关税  
        orderDecorator = new TariffDiscountDecorator(orderDecorator, 0.3); 

        double process = orderDecorator.process(400D); 
        System.out.println("订单实际金额:" + process); 
    } 
} 

重构后效果

系统改进点
  • 动态组合:运行时任意组合功能
  • 正交扩展:新增装饰器不影响现有逻辑
  • 类型安全:所有装饰器实现统一接口
  • 顺序敏感:装饰顺序影响最终结果(符合业务特性)
复杂度对比
指标 重构前 重构后
类数量 O(2ⁿ) O(n)
新增功能成本 修改现有类 新增装饰器类
测试覆盖率 60% 95%

赠品需求实现

kotlin 复制代码
public class GiftDecorator extends OrderDecorator { 
    private final String giftName; 

    protected GiftDecorator(OrderProcessor processor, String giftName) { 
        super(processor); 
        this.giftName = giftName; 
    } 

    @Override 
    public double process(Double amount) { 
        System.out.println("------------------订单赠品处理------------------"); 
        System.out.println("商品订单金额:" + amount); 
        System.out.println("商品赠品名称:" + giftName); 
        System.out.println("-----------------------------------------------"); 
        return super.processor.process(amount); 
    } 
} 

测试代码

ini 复制代码
public class OrderProcessorTest { 
    @Test 
    public void discountTest() { 
        OrderProcessor orderDecorator = new OrderProcessorImpl(); 

        orderDecorator = new GiftDecorator(orderDecorator, "灰太狼玩偶"); 
        orderDecorator = new DiscountDecorator(orderDecorator, 0.1); 
        orderDecorator = new TariffDiscountDecorator(orderDecorator, 0.3); 

        double process = orderDecorator.process(400D); 
        System.out.println("订单实际金额:" + process); 
    } 
} 

团队新日常

小易(转着笔):"加个新功能?写个装饰器五分钟搞定~" 老李(喝着茶):"测试用例都不用改,舒坦!"
小美(星星眼):"易哥,今晚我请喝奶茶!"

长话短说

核心思想:通过组合实现功能的动态叠加,保持类职责单一性(想加功能就加层装饰,拆开来看每个装饰器只管一件事)

何时选择装饰器模式?

  • 需要动态、透明地扩展对象功能
  • 不宜使用子类扩展(避免类爆炸)
  • 需要运行时组合不同功能

何时避免使用?

  • 扩展功能需要完全改变接口
  • 装饰顺序不影响结果时(可能过度设计)
  • 性能敏感的底层操作(装饰器可能引入开销)

适用场景特征

  1. 需要动态、透明地添加职责
  2. 不能使用继承或需要避免子类膨胀
  3. 需要撤销或替换已添加的功能

代码编写步骤

  1. 定义组件接口(OrderComponent)
  2. 创建基础实现类(BasicOrder)
  3. 创建装饰器基类(OrderDecorator)
  4. 实现具体装饰器(ImportTaxDecorator)
  5. 客户端按需组合装饰器

示例代码结构

kotlin 复制代码
public interface Component { ... }          // 组件接口 
public class ConcreteComponent implements Component { ... }  // 基础实现类  
public abstract class Decorator implements Component { ... } // 装饰器基类  
public class ConcreteDecoratorA extends Decorator { ... }    // 具体装饰器 A
public class ConcreteDecoratorB extends Decorator { ... }    // 具体装饰器 B
相关推荐
s91236010117 分钟前
【rust】生成带白边的标准二维码
开发语言·后端·rust
刘立军24 分钟前
本地大模型编程实战(38)实现一个通用的大模型客户端
后端·llm
李拾叁的摸鱼日常37 分钟前
为什么mysql varchar 类型一般都设置为64/128/256/512 ?
后端·架构
踏浪无痕42 分钟前
每天上亿条日志,Elasticsearch 是怎么扛住的?
后端·架构·设计
没有bug.的程序员1 小时前
JVM 与 Docker:资源限制的真相
java·jvm·后端·spring·docker·容器
思维新观察1 小时前
谷歌发新 XR 设备:眼镜能识零食热量,头显能转 3D 影像
后端·xr·ai眼镜
申阳1 小时前
Day 23:登录设计的本质:从XSS/CSRF到Session回归的技术演进
前端·后端·程序员
古城小栈1 小时前
Spring Boot 4.0 虚拟线程启用配置与性能测试全解析
spring boot·后端·python
松莫莫1 小时前
Spring Boot 整合 MQTT 全流程详解(Windows 环境)—— 从 Mosquitto 安装到消息收发实战
windows·spring boot·后端·mqtt·学习
小码编匠1 小时前
WPF 实现高仿 Windows 通知提示框:工业级弹窗设计与实现
后端·c#·.net