九阴真经-策略模式实战

前言

有很多人感叹自己整天做着CRUD的活,想去做高并发高流量的项目。

以我现在的理解来看,并发只有1,2,无穷的区别,你是否考虑过你现在的接口在同时被访问的时候是否会出现问题。比如1个订单有3个货物需要发货,同时对1,2 和 2,3进行了发货,这个时候不做控制,会导致我们的数据紊乱。
从1到2的并发,对应的解决方案为分布式锁,乐观锁等。
从2到无穷的并发,对应的解决方案,缓存,异步,集群,分库分表,限流熔断降级等。

而本文讲解的策略模式是提高代码可维护性的一个解决方案。

开始

但凡学习过设计模式的同学都知道策略模式可以用来解决代码中过多的if/else。其实这个说法有点不准确,策略模式所解决的if/else逻辑是针对同一个模式的不同策略扩展。使用if/else的缺点是,代码冗长并且扩展性差,我新加一个else分支后,需要改动主流程代码,导致需要回归全部分支。

而使用了策略模式后,主流程的代码会根据不同模式选择具体策略接口实现,新增策略模式,只需要增加扩展类即可。

举一个计算订单价格的例子,不使用策略模式前代码如下

if(里程包){
    //计算价格逻辑为根据车辆合同价选择对应单价*购买公里数
}else if(保险){
    //保险合约中剩余天数/365*保险单价
}else if(普通商品){
    //商品单价*件数*折扣
}
...

使用策略模式后

PriceCalculateStrategy strategy = strategyContainer.get(商品类型)
price = strategy.calculate(...)

PriceCalculateStrategy针对不同商品类型有不同实现

并且之后新增其他商品类型,我们只需要新增一个策略实现即可。

从面向对象设计原则来看,第一,负责对修改封闭对扩展开放的原则,第二,我们的计算逻辑内聚在策略类中。

上面只是一些伪代码,在实际编程中使用策略模式时,我们一般和spring相结合,大致流程如下

  1. 实现策略接口,并且用注解或其他方式标识该策略对应那种模式
  2. 注册到spring容器,并且由另外一个单独管理类负责读取
  3. 业务代码中从管理类获取对应策略实现类调用

有没有发现一个问题,对于每一个策略接口我们都需要设计一个策略管理类,并且针对不同标识方式还需要微调管理类代码,很容易手残出错。

因此,我结合spring特性设计了一个小框架,让大家只需要关注策略的实现。

策略框架

假设现在有一个策略接口如下

public interface HelloStrategy {

    String hello();
}

然后这个策略会有不同实现,并且我们需要标识出来,这个框架用的是注解方式。

@People(district = "chinese",gender = GenderEnum.FEMALE)
public class ChineseGirlHelloStrategy implements HelloStrategy {
    @Override
    public String hello() {
        return "你好";
    }
}

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Component
public @interface People {

    String district();

    GenderEnum gender();

}

@People注解是自定义注解,这个框架也支持通用的内置注解
然后我们只增加一个Bean的配置

@Bean
public StrategyContainerFactoryBean helloStrategyContainer(){
    return StrategyContainerFactoryBean.build(HelloStrategy.class,People.class,a -> Joiner.on(",").join(a.district(),a.gender().name()));
}

其中a -> Joiner.on(",").join(a.district(),a.gender().name())用来解析注解生成对应标识符

最后在业务代码中注入StrategyContainer进行使用

@Resource(name = "helloStrategyContainer")
private StrategyContainer helloStrategyContainer;

HelloStrategy helloStrategy = helloStrategyContainer.getStrategy(Joiner.on(",").join("chinese", GenderEnum.FEMALE.name()));
helloStrategy.hello()

这边需要注意的是从helloStrategyContainer获取策略的逻辑需要和注解解析标识符一致。

这个项目已经在我所在项目使用,还是节约了相当一部分和业务无关的代码,让开发更高效。

项目地址为https://github.com/shengchaojie/spring-strategy-extend ,欢迎star

你可能感兴趣的:(九阴真经-策略模式实战)