行为型模式之策略模式(枚举优化)

2023-03-01  本文已影响0人  雪飘千里

行为型模式之策略模式介绍了策略模式的概念和用法,工作中可以借助枚举更加优雅的实现。

方法一:枚举+自动注入

一、建造枚举类

/**
 * 策略方法枚举
   */
   public enum EventEnum {

   /**
    * 用户新增事件
      */
      USER_ADD_ORG("user_add_org","UserTypeAddService","用户新增事件"),

   /**
    * 用户更改
      */
      USER_MODIFY_ORG("user_modify_org","UserModifyService","通讯录用户更改"),


    public static EventEnum getValue(String eventType) {
        for (EventEnum loginEnum : EventEnum.values()) {
            if (loginEnum.getEventType().equals(eventType)) {
                return loginEnum;
            }
        }
        return null;
    }

    private String eventType;
     
    private String serviceName;
     
    private String desc;

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

二、编写策略接口

 public interface EventTypeInterface {

   /**
    * @return
      */
      String eventType();
}

 // 用户修改实现类:
 @Service("UserModifyService")
 public class UserModifyService implements EventTypeInterface {
    @Override
    public String eventType() {
        return "我是用户修改";
    }
}


 //用户新增实现类:
 @Service("UserTypeAddService")
 public class UserTypeAddService implements EventTypeInterface {
    @Override
    public String eventType() {
        return "我是用户新增";
    }
}

三、编写获取上下文方法类

@Service
public class EventSpringContext {
    
   //Autowired自动注入EventTypeInterface实现类,key类名称
   @Autowired
   private final Map<String, EventTypeInterface> strategyMap = new ConcurrentHashMap<>(4);


   /**
    * 根据事件类型获取不同策略
    * @param loginType
    * @return
      */
      public EventTypeInterface getService(String loginType) {
        EventEnum eventEnum = EventEnum.getValue(loginType);
        return strategyMap.get(eventEnum.getServiceName());
      }
  }

四、建立测试方法

@GetMapping("test1")
public String getTests(String eventType){
    System.out.println("进来事件"+eventType);
    EventTypeInterface service = eventSpringContext.getService(eventType);
    String type= service.eventType();
    System.out.println("返回结果"+eventType);
    return eventType;
}

方法二:纯枚举

一、建造枚举类

package com.example.springbootdemo;

public enum ValidatorStrategy {
    
    XML {
        @Override
        void doValidation(String content) {
            System.out.println("This is a XML content");
        }

    },

    JSON {
        @Override
        void doValidation(String content) {
            System.out.println("This is a JSON content");
        }
    },

    YAML {
        @Override
        void doValidation(String content) {
            System.out.println("This is a YAML content");
        }
    },

    CSV {
        @Override
        void doValidation(String content) {
            System.out.println("This is a CSV content");
        }
    };

    abstract void doValidation(String content);
}

二、编写获取上下文方法类

public class ValidatorContext {

    private ValidatorStrategy strategy;

    public ValidatorContext(ValidatorStrategy strategy) {
        this.strategy = strategy;
    }

    
    public void runValidation(String content) {
        strategy.doValidation(content);
    }

}

三、建立测试方法

@GetMapping("test1")
public String getTests(String eventType){
    ValidatorContext validator = new ValidatorContext(ValidatorStrategy.XML);
    validator.runValidation("XML content"); 
}

方法三:枚举+工厂

一、建造枚举类

package com.ultiwill.strategy.enums;

import org.apache.commons.lang.StringUtils;

public enum PayEnumStrategy {
    /**
     * 阿里支付
     */
    ALI_PAY("1","com.ultiwill.strategy.impl.AliPayStrategy"),
    /**
     * 微信支付
     */
    WECHAT_PAY("2","com.ultiwill.strategy.impl.WeChatPayStrategy"),
    /**
     * 小米支付
     */
    XIAOMI_PAY("3","com.ultiwill.strategy.impl.XiaomiPayStrategy");


    private String code;
    private String className;

    PayEnumStrategy() {
    }

    PayEnumStrategy(String code, String className) {
        this.code = code;
        this.className = className;
    }

    public static String getClassNameByCode(String code) {
        String className = "";
        if (StringUtils.isEmpty(code)) {
            return className;
        }

        for (PayEnumStrategy e : PayEnumStrategy.values()) {
            if (e.code.equalsIgnoreCase(code)) {
                className = e.className;
                break;
            }
        }
        return className;
    }
}

二、编写策略接口

package com.ultiwill.strategy;

public interface PayStrategy {

    /**
     * 共同的行为方法
     * @return
     */
    String toPayHtml();

}

三种具体策略的实现 (阿里支付, 微信支付, 小米支付)

public class AliPayStrategy implements PayStrategy {
    @Override
    public String toPayHtml() {
        return "调用阿里支付...AliPayStrategy";
    }
}


public class WeChatPayStrategy implements PayStrategy {
    @Override
    public String toPayHtml() {
        return "调用微信支付...WeChatPayStrategy";
    }
}

public class XiaomiPayStrategy implements PayStrategy {
    @Override
    public String toPayHtml() {
        return "调用小米支付...XiaomiPayStrategy";
    }
}

三、编写策略工厂

package com.ultiwill.strategy.factory;

import com.ultiwill.strategy.PayStrategy;
import com.ultiwill.strategy.enums.PayEnumStrategy;


public class StrategyFactory {

    /**
     * 使用策略工厂获取具体策略实现
     * @param code
     * @return
     */
    public static PayStrategy getPayStrategy(String code) {
        try {
            return (PayStrategy) Class.forName(PayEnumStrategy.getClassNameByCode(code)).newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return null;
    }
}

四、编写获取上下文方法类

package com.ultiwill.strategy.context;

import com.ultiwill.strategy.PayStrategy;
import com.ultiwill.strategy.enums.PayEnumStrategy;
import com.ultiwill.strategy.factory.StrategyFactory;
import org.apache.commons.lang.StringUtils;

/**
 * 上下文
 */
public class PayContextStrategy {

    /**
     * 获取具体的策略实现
     *
     * @param code
     * @return
     */
    public static String toPayHtml(String code) {
        if (StringUtils.isBlank(code)) {
            return "code不能为空...";
        }
        PayStrategy payStrategy = StrategyFactory.getPayStrategy(code);
        if (payStrategy == null) {
            return "没有找到具体的策略...";
        }
        return payStrategy.toPayHtml();
    }
}

五、测试

@RestController
public class TestController {
    @RequestMapping("/helloworld")
    public String hello(String code) {
        return PayContextStrategy.toPayHtml(code);
        /*if ("0".equals(code)) {
            return "调用阿里支付...AliPayStrategy";
        } else if ("1".equals(code)) {
            return "调用微信支付...AliPayStrategy";
        } else if ("2".equals(code)) {
            return "调用小米支付...AliPayStrategy";
        }
        return "调用接口不存在";
        */
    }
}

总结:代码也是在进化的,最早用到的是第三种方式,但是很明显,使用工厂反射创建实现类一点也不优雅,现在已经很少用了。

第一种方法和第二种方法的区别就在是否在枚举中实现

最流行的还是第一种方式和第二种方式,区别是如果业务复杂,那还是要用接口单独实现,但是如果业务简单,比如一些字符串拼接,或者时间格式化,或者校验,那么就可以直接在枚举中实现。

上一篇 下一篇

猜你喜欢

热点阅读