业务代码中如何使用装饰器模式?

装饰器模式(Decorator Pattern)介绍

装饰器模式(Decorator Pattern)是一种结构型设计模式,我们可以动态地给一个对象添加额外的职责。而不是通过继承增加子类的方式来扩展对象的功能,装饰器模式使用组合的方式来增强对象的功能,这有助于保持类的职责单一,提高了类的复用性和灵活性。

装饰器模式通常涉及以下角色:

  • • 组件(Component)接口:定义了一个对象接口,可以动态地给这些对象添加职责。
  • • 具体组件(Concrete Component):实现了组件接口的对象,这是我们要动态添加职责的对象。
  • • 装饰器(Decorator)类:实现了组件接口的抽象类,并持有一个组件接口的引用。这个类的任务是定义那些可以动态添加的职责。
  • • 具体装饰器(Concrete Decorator):实现了装饰器类的具体类,负责给组件添加新的职责。

优缺点

优点:

  • • 扩展对象功能:装饰器模式提供了一种灵活的替代方案来扩展对象的功能,比继承更灵活。
  • • 动态添加职责:可以动态地添加或删除对象的职责。
  • • 复合而非继承:通过使用组合而非继承的方式,避免了在层级关系上造成静态的继承关系,提高了代码的可复用性和灵活性。

缺点:

  • • 增加系统复杂性:使用大量的小类,可能会增加系统的复杂度。
  • • 多层装饰比较复杂:当装饰链过长时,会增加系统的复杂度,并且调试时可能会带来不便。

Spring Boot中业务代码示例

假设我们有个下单流程计算价格,现在我们需要新增一个打折优惠。怎么不修改原来代码巧妙的增加我们的功能呢?通过装饰器模式将不同的折扣策略作为装饰层动态添加到订单处理流程中。这样,我们可以在不修改现有类的情况下,灵活地添加或修改折扣策略。

订单接口

首先,定义一个订单服务接口,这是我们的组件接口:

csharp 复制代码
public interface OrderService {
    double applyDiscount(double orderTotal);
}

实现一个基本的订单服务:

java 复制代码
@Component
public class SimpleOrderService implements OrderService {
    @Override
    public double applyDiscount(double orderTotal) {
        // 默认情况下,没有任何折扣
        return orderTotal;
    }
}

装饰器实现

接着,我们创建一个装饰器抽象类:

java 复制代码
@Component
public abstract class OrderServiceDecorator implements OrderService {
    @Resource
    protected OrderService simpleOrderService;

    @Override
    public double applyDiscount(double orderTotal) {
        return simpleOrderService.applyDiscount(orderTotal);
    }
}

定义不同的折扣策略作为装饰器:

java 复制代码
@Component
public class PercentageDiscountDecorator extends OrderServiceDecorator {

    @Override
    public double applyDiscount(double orderTotal) {
        // 折扣率
        double discountRate = 0.2;
        double discount = orderTotal * discountRate;
        return super.applyDiscount(orderTotal - discount);
    }
}

整体结构如下

测试一下

java 复制代码
@SpringBootApplication
public class DecoratorPatternApplication {

    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(DecoratorPatternApplication.class, args);

        OrderService percentageService = context.getBean(PercentageDiscountDecorator.class);

        double orderTotal = 300.0;
        double discountedTotal = percentageService.applyDiscount(orderTotal);
        System.out.println("Discounted order total: " + discountedTotal);
    }
}

在这个例子中,通过PercentageDiscountDecorator 添加了百分比折扣。通过这种方式,我们可以根据需要灵活地组合和应用不同的折扣策略,而不必更改现有的订单服务代码。这种方法提高了代码的可维护性和扩展性,同时也保持了业务逻辑的清晰性。

与策略模式区别

之前分享过策略模式的实现:如何在业务代码中优雅的使用策略模式

我们回顾下策略模式的特征:策略模式定义了一系列的算法,并将每一个算法封装起来,使它们可以互相替换。策略模式让算法独立于使用它的客户端而变化,即分离了算法的定义和使用,客户端代码通过依赖注入的方式选择使用哪一种策略。

在我们上面的示例中,如果使用装饰器模式,我们可以动态地为订单服务添加额外的功能(如折扣),而每个装饰器都可以独立地添加额外的职责。

而如果使用策略模式来处理折扣,我们可能会定义一个折扣策略接口,然后为每种折扣定义一个具体的策略类。客户端代码决定使用哪一种折扣策略,并将其应用于订单总额上。这里,策略是静态选择的,并且一次只能应用一个策略。

装饰器模式强调的是如何动态地添加职责,而策略模式强调的是如何封装算法和行为,并在它们之间切换。

相关推荐
Tiny_React几秒前
智能体设计模式-CH05:工具使用(Tool Use)
设计模式
文心快码BaiduComate1 分钟前
新手如何高效使用 Zulu 智能体?从入门到提效全指南
前端·后端
G探险者1 分钟前
云原生时代下的 JVM 内存管理:为什么你的服务不会“自动扩容”?
后端·云原生
舒克起飞了4 分钟前
设计模式——建造者模式
设计模式·建造者模式
渣哥5 分钟前
还在写繁琐监听器?Spring @EventListener 注解让你代码瞬间简化
javascript·后端·面试
Tiny_React6 分钟前
智能体设计模式-CH06:规划(Planning)
设计模式
搞笑我们是认真的_______狗才写代码8 分钟前
技术总监:学着点,我们团队就缺这样的人才
后端
马尚来10 分钟前
掌握Kotlin编程,从入门到精通:视频教程
后端·kotlin
爱吃烤鸡翅的酸菜鱼11 分钟前
从零掌握贪心算法Java版:LeetCode 10题实战解析(上)
java·算法
yeyong11 分钟前
将所有的服务都放在里面做一个容器用supervisor管理进程 VS 用很多容器跑单独应用并集成一套,哪种更好?
后端