阅读 39

策略模式配合枚举类的一个记录

策略模式配合枚举类

在项目中碰到一个根据循环类型(天、周、月等)获取一个时间偏移量的问题。一开始我的想法是通过ifelse判断类型,但这样就会有多层的if判断。

public void demo(){
    Integer type = A.getType();
    if(type == Type.DAY.getCode()){
        ...
    }
    if(type == Type.DAY.getCode()){
        ...
    }
	...
}


public enum Type{
    DAY(1,"天"),
    WEEK(2,"周"),
    ...
    ;
    private final Integer code;
    private final String info;
	...
}


复制代码

多层的if,让我突然想起来前几天看到阿里巴巴Java开发手册中有一句话

image-20210422110401066.png

那么就使用策略模式来试着优化一下吧!

策略模式

​ 首先我们需要一个抽象策略接口

//抽象策略接口
public interface IStrategy{
    void function();
}
复制代码

​ 然后,我们需要让他实现不同的实体类

// 例如 这个AAA策略
public class AAAStrategy implements IStrategy{
    @Override
    public void function(){
		System.out.println("这里是AAA策略实现类...");
    }
}

// BBB策略
public class BBBStrategy implements IStrategy{
    @Override
    public void function(){
        System.out.println("这里是BBB策略实现类...");
    }
}

复制代码

​ 接下来,我们还需要一个可以让我们控制使用哪种策略的控制类

public class StrategyHandler{
    //定义一个内部属性为 抽象策略接口
    private IStrategy iStrategy;
    
    //实现一个set方法 让我们能够指定选择策略
    public void setIStrategy(IStrategy iStrategy){
        this.iStrategy = iStrategy;
    }
    
    //统一策略方法入口
    public void strategyFunction(){
        iStrategy.function();
    }
}
复制代码

​ 到这里我们的策略方法就写完啦,那么如何使用呢?

​ 其实很简单,看代码

public void demo(){
    //得到handle控制类
    StrategyHandle handle = new StrategyHandle();
    //指定策略方法
    handle.setIStrategy(new AAAStrategy());
    //使用统一策略方法入口
    handle.strategyFunction();
}
复制代码

​ 这样我们的策略模式也就实现了,但是回过头看看实际项目需求,我突然发现对于设置策略方法他还是需要一段段的if去判断(怎么会这样.jpg)

​ 就像这样

public void demo(){
    Integer type = 实现类.getType();
    //得到handle控制类
    StrategyHandle handle = new StrategyHandle();
    //指定策略方法
    if(type == 1){
        //指定A策略
    }
    if(type == 2){
        //指定B策略
    }
    ...
}
复制代码

​ 阿巴阿巴阿巴,我到底写了个什么。

配合枚举

​ 之后呢,思考了一会该怎么避免,我突然想到为什么我不把策略放到枚举类中

//像这样
public enum Type{
    A(1,new AAAStrategy),
    B(2,new BBBStrategy);
    private final Integer code;
    private final IStrategy iStrategy;
    
    //这里有一个getIStrategy方法
    public IStrategy getIStrategy(){
        ...
    }
    
    //这里有一个 根据code 获得对于Strategy方法
    public static ICycleStrategy getStrategyByCode(Integer code){
    }

    
}
复制代码

​ 那么之前的结果就变成了

public void demo(){
    Integer type = 实现类.getType();
    //得到handle控制类
    StrategyHandle handle = new StrategyHandle();
    //获取对应策略
    IStrategy iStrategy = Type.getStrategyByCode(type);
  	//指定策略方法
    handle.setIStrategy(iStrategy)
    
    //方法入口
    ...
}
复制代码

image-20210423135713856.png

​ 完美!


感谢导师提醒,突然发现如果把具体的实现类放入枚举类的属性当中,那么handler大概就不需要了 最后的结果就是直接获取枚举当中策略然后执行方法
    //像这样
    public void demo(){
        Integer type = 实现类.getType();
        //获取对应策略
        IStrategy iStrategy = Type.getStrategyByCode(type);
        //方法入口
        iStrategy.function();
        ...
}
复制代码

总结

​ 我尝试在枚举类中放入对于的实现策略,这样就可以通过数据库的值变化,来变换不同的策略。

​ 那么增加和删除对业务代码也不会做改动,只需要实现或者删除一个策略实现类,再增加一个枚举就可以了。

进一步优化的想法

这些天看了一些文章,对于进一步的优化有了新的想法:

  1. 优化策略模式带来的策略类的增加 -> 内部类 -> 匿名内部类
  2. 对于大量策略的增加 内部类依旧不吃好 -> 加入函数式接口以及lamda表达式
  3. 对于其他类型的扩展 -> 优化为泛型
文章分类
后端
文章标签