通过枚举类实现策略模式的上下文切换

文章讨论了Java代码中通过依赖注入和枚举类两种方式实现策略切换的场景,强调了依赖注入的灵活性与反射带来的性能和复杂性问题,同时介绍了枚举类实现策略的优点,如封装性、类型安全和扩展性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、让我们先来看一段非常蠢的策略切换

 // 将所有的策略类以list的形式注入
 @Resource
 private List<PoiExtExtraInfoToBService> poiExtExtraInfoToBServices;


// 通过反射获取策略类的code值然后比对入参code得到所需策略类
List<PoiExtExtraInfoToBService> satisfyServices = poiExtExtraInfoToBServices.stream().filter(poiExtExtraInfoToBService ->
                        reqDTO.getPoiExtCategoryId().equals(poiExtExtraInfoToBService.getClass().getAnnotation(PoiExtBizCategory.class).bizCategoryId())).collect(Collectors.toList());

这段Java代码主要实现了以下功能:

  1. 依赖注入策略类列表:使用了 @Resource 注解来自动注入实现了 PoiExtExtraInfoToBService 接口的所有类的实例列表。这些策略类的实例被存储在名为 poiExtExtraInfoToBServicesList 集合中。

  2. 筛选特定策略实现:通过使用流(Stream)操作,从 poiExtExtraInfoToBServices 列表中筛选出符合特定条件的策略实现。这个条件是策略实现类上的 @PoiExtBizCategory 注解中的 bizCategoryId 属性值与请求DTO (reqDTO) 中的 poiExtCategoryId 属性值相匹配。

  3. 使用反射获取注解值:在筛选过程中,代码使用了反射来访问每个策略实现类上的 @PoiExtBizCategory 注解,特别是该注解的 bizCategoryId 属性。反射是必要的,因为这些值在运行时被用来动态确定哪些策略类与当前请求的类别ID匹配。

  4. 收集匹配的策略实现:匹配的策略实现被收集到一个新的列表 satisfyServices 中,这个列表包含所有其类别ID符合条件的策略实现实例。

这段代码的详细流程如下:

  • 流程开始:从 poiExtExtraInfoToBServices 列表中开始一个流式处理。
  • 筛选(Filter):对于列表中的每一个元素(每个策略实现),执行以下操作:
    • 获取该策略实现类的 Class 对象。
    • 通过 getClass().getAnnotation(PoiExtBizCategory.class) 获取该类上的 PoiExtBizCategory 注解。
    • 从注解实例中获取 bizCategoryId 值。
    • 将此值与 reqDTO 中的 poiExtCategoryId 进行比较。
    • 如果这两个值相等,说明这个策略实现是符合条件的。
  • 收集结果:使用 collect(Collectors.toList()) 将所有符合条件的策略实现收集到一个新的列表 satisfyServices

缺点:

  1. 性能影响:反射是一个相对昂贵的操作,特别是在大量调用时。访问注解和属性通过反射进行,会比直接的方法调用慢。在性能敏感的应用中,频繁使用反射可能成为瓶颈。

  2. 代码复杂性:使用反射和流式API虽然在功能上非常强大,但这也可能使代码更难理解和维护。特别是反射部分,错误处理和调试可能会更加困难,因为反射操作的错误可能不会在编译时被捕获,而是在运行时显现。

  3. 安全性问题:如之前所述,反射可以绕过Java的访问控制机制,访问私有和受保护的成员。这可能导致意外的行为或安全漏洞,特别是在不正确地管理反射访问权限的情况下。

  4. 封装性破坏:反射的使用可能会破坏对象的封装性,因为它允许外部代码访问和修改类的内部状态。这与面向对象编程的基本原则相违背,可能会导致代码难以维护和扩展。

  5. 代码的可靠性:由于反射依赖于运行时的动态类型信息,任何重构活动(如重命名字段或移除方法)都可能不被反射代码正确识别,从而导致运行时错误。

  6. 类型安全问题:反射操作通常不是类型安全的。这意味着如果注解或其属性的类型在未来更改,相关的反射代码可能会失败,且这种失败只能在运行时被检测到。

  7. 注入了不必要的策略类:在定制化逻辑中注入了不必要的策略类,使业务变得难以理解。

二、通过枚举类实现策略的上下文切换

/**
 *  枚举类,定义了业务分类的枚举值
 */
public enum BizCategoryEnum {


    HOME_DECORATION_DESIGN_SPECIAL_SERVICE(60103, "家居装修设计特色服务", new HomeDecorationDesignSpecialServiceStrategyImpl()),

    DISCOVERY_VIDEO(28904,"探店视频", new DiscoveryVideoStrategyImpl());

    private final Integer code;
    private final String desc;
    private final BizCategoryStrategy strategy;

    BizCategoryEnum(Integer code, String desc, BizCategoryStrategy strategy) {
        this.code = code;
        this.desc = desc;
        this.strategy = strategy;
    }

    public Integer getCode() {
        return code;
    }

    public String getDesc() {
        return desc;
    }

    public void executeStrategy(ProcessorContext context) {
        strategy.invoke(context);
    }

    public static BizCategoryEnum fromCode(Integer code) {
        for (BizCategoryEnum value : values()) {
            if (value.getCode().equals(code)) {
                return value;
            }
        }
        return null;
    }

}


// 执行策略
BizCategoryEnum category = BizCategoryEnum.fromCode(context.getPoiExtCategoryId());
if (category != null) { // 确保枚举值不是null
    category.executeStrategy(context);
}

这段代码演示了如何在Java中使用枚举来实现策略模式,优雅地结合了业务逻辑的封装和策略执行。下面是对这个实现的详细分析:

枚举类 BizCategoryEnum 说明

  1. 定义枚举值

    • 每个枚举值(如 HOME_DECORATION_DESIGN_SPECIAL_SERVICEDISCOVERY_VIDEO)都关联了一个唯一的业务代码(code)、描述(desc)以及具体的策略实现(strategy)。这些策略实现都实现了某个 BizCategoryStrategy 接口。
  2. 字段

    • code:业务分类的唯一代码。
    • desc:对业务分类的描述。
    • strategy:具体的策略实现,用于执行与业务分类相关的特定逻辑。
  3. 构造函数

    • 构造函数接收业务代码、描述和策略实现,为每个枚举值设置这些属性。
  4. 方法

    • getCode()getDesc():提供对枚举值属性的访问。
    • executeStrategy(ProcessorContext context):调用策略实现的 invoke 方法,传入上下文,执行策略。
    • fromCode(Integer code):静态方法,根据传入的业务代码查找对应的枚举值。这是实现策略选择的关键方法。

使用示例

  • 策略执行逻辑
    • 使用 fromCode 方法根据上下文中的业务代码查找相应的枚举值。
    • 如果找到相应的枚举值,调用 executeStrategy 方法执行关联的策略。

优点

  • 封装性:将业务代码、描述和策略实现封装在枚举值中,易于管理和使用。
  • 类型安全:使用枚举保证了类型安全,避免了使用字符串或整数常量的潜在错误。
  • 易于扩展:新增业务分类和策略时,只需添加新的枚举值即可。
  • 清晰的业务逻辑分离:通过分离策略接口和具体实现,保持了代码的模块化和高内聚。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值