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

装饰器模式(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 添加了百分比折扣。通过这种方式,我们可以根据需要灵活地组合和应用不同的折扣策略,而不必更改现有的订单服务代码。这种方法提高了代码的可维护性和扩展性,同时也保持了业务逻辑的清晰性。

与策略模式区别

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

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

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

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

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

相关推荐
程序员爱钓鱼2 分钟前
Go语言泛型-泛型对代码结构的优化
后端·google·go
这里有鱼汤7 分钟前
“对象”?对象你个头!——Python世界观彻底崩塌的一天
后端·python
RainbowSea10 分钟前
跨域问题(Allow CORS)解决(3 种方法)
java·spring boot·后端
掘金-我是哪吒11 分钟前
分布式微服务系统架构第155集:JavaPlus技术文档平台日更-Java线程池实现原理
java·分布式·微服务·云原生·架构
RainbowSea14 分钟前
问题 1:MyBatis-plus-3.5.9 的分页功能修复
java·spring boot·mybatis
前端 贾公子17 分钟前
monorepo + Turborepo --- 开发应用程序
java·前端·javascript
鼠鼠我呀233 分钟前
【设计模式04】单例模式
单例模式·设计模式
不学会Ⅳ1 小时前
Mac M芯片搭建jdk源码环境(jdk24)
java·开发语言·macos
虫小宝1 小时前
高佣金返利平台监控体系建设:APM、链路追踪与佣金异常预警系统技术实现
java
sniper_fandc2 小时前
SpringBoot系列—入门
java·spring boot·后端