原理

在策略模式中,我们创建表示各种策略的对象和一个行为随着策略对象改变而改变的 context/service 对象。策略对象改变 context/service 对象的执行算法。

具体案例

项目结构如下:

策略模式例子项目结构

  • AbstractHandler是所有策略的父类,定义了策略的执行抽象方法。
  • EventEnum是事件枚举。
  • HandlerParma是执行service传入的参数,封装了事件类型和待解析的参数。
  • HandlerRes是策略的执行结果。
  • LoginHandler是一个具体的策略实现类。
  • HandlerService是一个服务类,用来根据HandlerParam调用不同的Handler。

AbstractHandler代码如下:

public abstract class AbstractHandler {
    
    /**
     * 执行策略
     */
    public abstract HandlerRes executeStrategy(HandlerParam param);
    
    /**
     * 本策略可以解决的事件类型
     */
    public abstract List<EventEnum> getEventTypes();
    
}

EventEnum代码如下:

public enum  EventEnum {

    /**
     * 登录事件类型
     */
    LOGIN("login","登录"),

    /**
     * 登出时间类型
     */
    LOGOUT("logout","登出");

    /**
     * @param value: 枚举value
     * @param desc: 描述
     */
    private String value,desc;

    public String getValue() {
        return value;
    }

    public String getDesc() {
        return desc;
    }


    EventEnum(String value, String desc) {
        this.value=value;
        this.desc=desc;
    }

    /**
     * 通过字符串获取对应的枚举
     */
    public EventEnum getEvent(String value){
        EventEnum[] values = EventEnum.values();
        for(EventEnum v:values){
            if(v.getValue().equals(value)){
                return v;
            }
        }
        return null;
    }
}

HandlerParam代码如下:

public class HandlerParam<T> {
    private EventEnum eventEnum;
    private T param;

    public HandlerParam(EventEnum eventEnum){
        this.eventEnum=eventEnum;
    }

    public HandlerParam(EventEnum eventEnum,T param){
        this.eventEnum=eventEnum;
        this.param=param;
    }


    public EventEnum getEventEnum() {
        return eventEnum;
    }

    public void setEventEnum(EventEnum eventEnum) {
        this.eventEnum = eventEnum;
    }

    public T getParam() {
        return param;
    }

    public void setParam(T param) {
        this.param = param;
    }

    @Override
    public String toString() {
        return "HandlerParam{" +
                "eventEnum=" + eventEnum +
                ", param=" + param +
                '}';
    }
}

HandlerRes代码如下:

public class HandlerRes<T> {
    private T res;

    public HandlerRes(){}

    public HandlerRes(T res){
        this.res=res;
    }

    public T getRes() {
        return res;
    }

    public void setRes(T res) {
        this.res = res;
    }

    @Override
    public String toString() {
        return "HandlerRes{" +
                "res=" + res +
                '}';
    }
}

LoginHandler代码如下:

@Component
public class LoginHandler extends AbstractHandler {
    @Override
    public HandlerRes executeStrategy(HandlerParam param) {
        Object v = param.getParam();
        System.out.println("执行了LoginHandler,传入参数为:"+v);
        return new HandlerRes<>("执行成功");
    }

    /**
     * 此策略支持:登录、登出两种事件
     */
    @Override
    public List<EventEnum> getEventTypes() {
        return Arrays.asList(EventEnum.LOGIN, EventEnum.LOGOUT);
    }
}

HandlerService代码如下:

@Service
public class HandlerService implements ApplicationContextAware {
    private ApplicationContext context;

    private Map<EventEnum, AbstractHandler> handlerMap=new HashMap<>();

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.context=applicationContext;
    }

    /**
     * 将handler策略装载到map中,map的key为事件类型,value为事件对应的策略
     */
    @PostConstruct
    public void init(){
        Map<String, AbstractHandler> beansOfType = context.getBeansOfType(AbstractHandler.class);
        for(Map.Entry<String,AbstractHandler> v:beansOfType.entrySet()){
            AbstractHandler handler = v.getValue();
            System.out.println("当前offType的String:"+v.getKey());
            List<EventEnum> eventTypes = handler.getEventTypes();
            if(eventTypes==null){
                continue;
            }
            for(EventEnum val:eventTypes){
                handlerMap.put(val,handler);
            }

        }
    }

    public HandlerRes strategy(HandlerParam param){
        AbstractHandler handler = handlerMap.get(param.getEventEnum());
        return handler.executeStrategy(param);
    }
}

测试代码如下:

@Test
void contextLoads() {
    HandlerParam<Integer> param = new HandlerParam<>(EventEnum.LOGOUT, 8454);
    HandlerRes strategy = service.strategy(param);
    System.out.println(strategy);
}

结果如下:

测试结果

总结

分离了变化的部分,让行为算法的变化独立于算法的使用者。可以减少if…else语句。需要不同的策略,只需实现不同的策略即可。