写代码的时候经常遇到这样的场景:根据某个字段值来进行不同的逻辑处理。例如,不同的会员等级在购物时有不同的折扣力度。如果会员的等级很多,那么代码中与之相关的if…elseif…else…会特别长,而且每新增一种等级时需要修改原先的代码。可以用策略模式来优化,消除这种场景下的if…elseif…else…,使代码看起来更优雅。
首先,定义一个接口
/** * 会员服务 */public interface VipService { void handle();}
然后,定义实现类
/** * 白银会员 */public class SilverVipService implements VipService { @Override public void handle() { System.out.println("白银"); }}/** * 黄金会员 */public class GoldVipService implements VipService { @Override public void handle() { System.out.println("黄金"); }}
最后,定义一个工厂类,目的是当传入一个会员等级后,返回其对应的处理类
public class VipServiceFactory { private static Map vipMap = new ConcurrentHashMap(); public static void register(String type, VipService service) { vipMap.put(type, service); } public static VipService getService(String type) { return vipMap.get(type); }}
为了建立会员等级和与之对应的处理类之间的映射关系,这里通常可以有这么几种处理方式:
方式一:实现类手动注册
可以实现InitializingBean接口,或者在某个方法上加@PostConstruct注解
import org.springframework.beans.factory.InitializingBean;import org.springframework.stereotype.Component;/** * 白银会员 */@Componentpublic class SilverVipService implements VipService, InitializingBean { @Override public void handle() { System.out.println("白银"); } @Override public void afterPropertiesSet() throws Exception { VipServiceFactory.register("silver", this); }}/** * 黄金会员 */@Componentpublic class GoldVipService implements VipService, InitializingBean { @Override public void handle() { System.out.println("黄金"); } @Override public void afterPropertiesSet() throws Exception { VipServiceFactory.register("gold", this); }}
方式二:从Spring容器中直接获取Bean
public interface VipService { void handle(); String getType();}/** * 白银会员 */@Componentpublic class SilverVipService implements VipService { @Override public void handle() { System.out.println("白银"); } @Override public String getType() { return "silver"; }}/** * 黄金会员 */@Componentpublic class GoldVipService implements VipService { @Override public void handle() { System.out.println("黄金"); } @Override public String getType() { return "gold"; }}/** * 上下文 */@Componentpublic class VipServiceFactory implements ApplicationContextAware { private static Map vipMap = new ConcurrentHashMap(); @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { Map map = applicationContext.getBeansOfType(VipService.class); map.values().forEach(service -> vipMap.put(service.getType(), service)); } public static VipService getService(String type) { return vipMap.get(type); }}/** * 测试 */@SpringBootTestclass DemoApplicationTests { @Test void contextLoads() { VipServiceFactory.getService("silver").handle(); }}
方式三:反射+自定义注解
@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)public @interface MemberLevel { String value();}@MemberLevel("silver")@Componentpublic class SilverVipService implements VipService { @Override public void handle() { System.out.println("白银"); }}@MemberLevel("gold")@Componentpublic class GoldVipService implements VipService { @Override public void handle() { System.out.println("黄金"); }}/** * 上下文 */@Componentpublic class VipServiceFactory implements ApplicationContextAware { private static Map vipMap = new ConcurrentHashMap(); @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {// Map map = applicationContext.getBeansOfType(VipService.class); Map map = applicationContext.getBeansWithAnnotation(MemberLevel.class); for (Object bean : map.values()) { if (bean instanceof VipService) { String type = bean.getClass().getAnnotation(MemberLevel.class).value(); vipMap.put(type, (VipService) bean); } } } public static VipService getService(String type) { return vipMap.get(type); }}
完整示例代码
/** * 结算业务种类 * @Author: ChengJianSheng * @Date: 2023/1/16 */@Getterpublic enum SettlementBusiType { RE1011("RE1011", "转贴现"), RE4011("RE4011", "买断式贴现"), RE4021("RE4021", "回购式贴现"), RE4022("RE4022", "回购式贴现赎回");// ...... private String code; private String name; SettlementBusiType(String code, String name) { this.code = code; this.name = name; }}/** * 结算处理器 * @Author: ChengJianSheng * @Date: 2023/1/16 */public interface SettlementHandler { /** * 清算 */ void handle(); /** * 获取业务种类 */ SettlementBusiType getBusiType();}/** * 转贴现结算处理 */@Componentpublic class RediscountSettlementHandler implements SettlementHandler { @Override public void handle() { System.out.println("转贴现"); } @Override public SettlementBusiType getBusiType() { return SettlementBusiType.RE1011; }}/** * 买断式贴现结算处理 */@Componentpublic class BuyoutDiscountSettlementHandler implements SettlementHandler { @Override public void handle() { System.out.println("买断式贴现"); } @Override public SettlementBusiType getBusiType() { return SettlementBusiType.RE4011; }}/** * 默认处理器 * @Author: ChengJianSheng * @Date: 2023/1/16 */@Componentpublic class DefaultSettlementHandler implements /*SettlementHandler,*/ ApplicationContextAware { private static Map allHandlerMap = new ConcurrentHashMap(); public static SettlementHandler getHandler(SettlementBusiType busiType) { return allHandlerMap.get(busiType); } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { Map map = applicationContext.getBeansOfType(SettlementHandler.class); map.values().forEach(e -> allHandlerMap.put(e.getBusiType(), e)); }}@SpringBootTestclass Demo2023ApplicationTests { @Test void contextLoads() { // 收到结算结果通知,根据业务种类进行结算处理 SettlementHandler handler = DefaultSettlementHandler.getHandler(SettlementBusiType.RE1011); if (null != handler) { handler.handle(); } }}