【策略模式】

业务场景中,当不同的意愿任务结束后,会有不同的动作,比如加密、解密、签署等。这些操作都是基于任务的类型进行区分,可以使用策略模式对代码进行优化,减少代码中的if…else…从而达到“对修改关闭,对扩展开放”的目的。后续再新增任务类型时,不会影响到其他任务类型的处理逻辑,减少测试回归的范围。

介绍

该模式定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的变化不会影响使用算法的客户。策略模式属于对象行为模式,它通过对算法进行封装,把使用算法的责任和算法的实现分割开来,并委派给不同的对象对这些算法进行管理。

如何实现一个策略模式

还是以意愿任务结束后,进行不同的动作举例。

定义任务类型枚举

public enum WillTaskTypeEnum {
    ENCRYPT_WILL("encryptWill", "加密场景"),
    DECRYPT_WILL("decryptWill", "解密场景"),
    SIGN_WILL("signWill", "签署场景"),;

    private String code;
    private String desc;

    private WillTaskTypeEnum(String code, String desc) {
        this.code = code;
        this.desc = desc;
    }

    private static final Map<String, WillTaskTypeEnum> codeMap = new HashMap<>();

    static {
        for (WillTaskTypeEnum willTaskTypeEnum : WillTaskTypeEnum.values()) {
            codeMap.put(willTaskTypeEnum.getCode(), willTaskTypeEnum);
        }
    }

    public static WillTaskTypeEnum fromCode(String code) {
        return codeMap.get(code);
    }

    public String getCode() {
        return this.code;
    }
}

定义抽象的策略类

策略类可以是接口,可以是抽象类。如果各个算法有通用的逻辑,可以使用抽象类加模板方法进行优化,模板方法就不展开来讲了。

public abstract class AbstractTaskStrategy {
    public abstract void execute(Object obj);
}

定义策略容器类,用于存放和获取策略

public class StrategyContext {

    private static final Map<String, AbstractTaskStrategy>
            strategyByWillTaskTypeMap = new HashMap<>();

    public static void addTaskStrategy(
            WillTaskTypeEnum willTaskTypeEnum, AbstractTaskStrategy strategy) {
        if (strategyByWillTaskTypeMap.containsKey(willTaskTypeEnum.getCode())) {
            throw new RuntimeException(willTaskTypeEnum + "策略重复");
        }
        strategyByWillTaskTypeMap.put(willTaskTypeEnum.getCode(), strategy);
    }

    public static AbstractTaskStrategy getTaskStrategy(
            String willTaskType) {
        if (StringUtils.isEmpty(willTaskType)) {
            return null;
        }
        return strategyByWillTaskTypeMap.get(willTaskType);
    }
}

定义策略实现类,并存放到策略容器中

目前项目基本都是使用Spring容器管理bean的创建,所以我们可以结合Spring Bean的生命周期,在bean创建之后,将策略类的bean放入到容器中。可以使用以下方法

步骤1. 将策略类跟任务类型关联
可以使用自定义注解表示可以处理的任务类型,或者在抽象类中自定义抽象方法,由子类实现表明自己可以处理哪种类型任务。此处我们使用自定义注解方式,定义自定义注解

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ProcessTask {

    WillTaskTypeEnum willTaskTypeEnum();

}

步骤2. 实现策略类
加密任务:

@ProcessTask(willTaskTypeEnum = WillTaskTypeEnum.DECRYPT_WILL)
@Component
public class DecryptTaskStrategyImpl extends AbstractTaskStrategy {
      public void execute(Object obj) {
          // TODO something....
    }
}

解密任务:

@ProcesshTask(willTaskTypeEnum = WillTaskTypeEnum.ENCRYPT_WILL)
@Component
public class EncryptTaskStrategyImpl extends AbstractTaskStrategy {
      public void execute(Object obj) {
          // TODO something....
    }
}

步骤3. 将策略实现类存入策略容器中

@Component
public class WillTaskBeanProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }
          // 在bean初始化完成之后放到策略容器中
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (!(bean instanceof AbstractTaskStrategy)) {
            return bean;
        }
        ProcesshTask annotation = bean.getClass().getAnnotation(ProcesshTask.class);
        if (Objects.isNull(annotation)) {
            return bean;
        }
        StrategyContext.addTaskStrategy(annotation.willTaskTypeEnum(), (AbstractTaskStrategy) bean);
        return bean;
    }
}

使用

@Component
public class Test {
  
      public void finishWill(WillTaskTypeEnum willTypeEnum, Object obj) {
          // 业务逻辑
          doBusiness(obj);
          // 调用策略
          afterWillSuccess(willTypeEnum, obj);
    }
  
      void doBusiness(Object obj) {
     
    }
  
      public void afterWillSuccess(WillTaskTypeEnum willTypeEnum, Object obj) {
         AbstractTaskStrategy abstractTaskStrategy = StrategyContext.get(willTypeEnum.getCode());
          if (Objects.isNull(abstractTaskStrategy)) {
              return;
        }
          abstractTaskStrategy.execute(obj);
    }
  
}

优点

后续再新增其他的任务类型时,业务主流程不会再改动,只需要新增新的策略即可。从而达到“对修改关闭,对扩展开放”的目的。

缺点

业务开发场景下,业务可能会经常变动,使用策略类之前要对业务有很好的抽象,明确当前策略要做什么事,入参和返回值一定要明确。否则某个业务需求变动,当前策略无法满足,入参或返回需要新增时,需要将所有策略实现类进行修改,代价可能比简单的if…else…更高。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值