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

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

与策略模式区别

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

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

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

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

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

相关推荐
ZZHow10243 小时前
JavaWeb开发_Day05
java·笔记·web
CHEN5_023 小时前
【Java虚拟机】垃圾回收机制
java·开发语言·jvm
Warren983 小时前
Lua 脚本在 Redis 中的应用
java·前端·网络·vue.js·redis·junit·lua
饕餮争锋5 小时前
设计模式笔记_行为型_观察者模式
笔记·观察者模式·设计模式
艾伦~耶格尔7 小时前
【数据结构进阶】
java·开发语言·数据结构·学习·面试
爪洼传承人7 小时前
18- 网络编程
java·网络编程
smileNicky7 小时前
SpringBoot系列之从繁琐配置到一键启动之旅
java·spring boot·后端
祈祷苍天赐我java之术7 小时前
Java 迭代器(Iterator)详解
java·开发语言
David爱编程8 小时前
为什么必须学并发编程?一文带你看懂从单线程到多线程的演进史
java·后端
我命由我123458 小时前
软件开发 - 避免过多的 if-else 语句(使用策略模式、使用映射表、使用枚举、使用函数式编程)
java·开发语言·javascript·设计模式·java-ee·策略模式·js