写代码的时候经常遇到这样的场景:根据某个字段值来进行不同的逻辑处理。例如,不同的会员等级在购物时有不同的折扣力度。如果会员的等级很多,那么代码中与之相关的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<String, VipService> 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; /** * 白银会员 */ @Component public class SilverVipService implements VipService, InitializingBean { @Override public void handle() { System.out.println("白银"); } @Override public void afterPropertiesSet() throws Exception { VipServiceFactory.register("silver", this); } } /** * 黄金会员 */ @Component public 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(); } /** * 白银会员 */ @Component public class SilverVipService implements VipService { @Override public void handle() { System.out.println("白银"); } @Override public String getType() { return "silver"; } } /** * 黄金会员 */ @Component public class GoldVipService implements VipService { @Override public void handle() { System.out.println("黄金"); } @Override public String getType() { return "gold"; } } /** * 上下文 */ @Component public class VipServiceFactory implements ApplicationContextAware { private static Map<String, VipService> vipMap = new ConcurrentHashMap<>(); @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { Map<String, VipService> map = applicationContext.getBeansOfType(VipService.class); map.values().forEach(service -> vipMap.put(service.getType(), service)); } public static VipService getService(String type) { return vipMap.get(type); } } /** * 测试 */ @SpringBootTest class DemoApplicationTests { @Test void contextLoads() { VipServiceFactory.getService("silver").handle(); } }
方式三:反射+自定义注解
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface MemberLevel { String value(); } @MemberLevel("silver") @Component public class SilverVipService implements VipService { @Override public void handle() { System.out.println("白银"); } } @MemberLevel("gold") @Component public class GoldVipService implements VipService { @Override public void handle() { System.out.println("黄金"); } } /** * 上下文 */ @Component public class VipServiceFactory implements ApplicationContextAware { private static Map<String, VipService> vipMap = new ConcurrentHashMap<>(); @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { // Map<String, VipService> map = applicationContext.getBeansOfType(VipService.class); Map<String, Object> 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 */ @Getter public 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(); } /** * 转贴现结算处理 */ @Component public class RediscountSettlementHandler implements SettlementHandler { @Override public void handle() { System.out.println("转贴现"); } @Override public SettlementBusiType getBusiType() { return SettlementBusiType.RE1011; } } /** * 买断式贴现结算处理 */ @Component public class BuyoutDiscountSettlementHandler implements SettlementHandler { @Override public void handle() { System.out.println("买断式贴现"); } @Override public SettlementBusiType getBusiType() { return SettlementBusiType.RE4011; } } /** * 默认处理器 * @Author: ChengJianSheng * @Date: 2023/1/16 */ @Component public class DefaultSettlementHandler implements /*SettlementHandler,*/ ApplicationContextAware { private static Map<SettlementBusiType, SettlementHandler> allHandlerMap = new ConcurrentHashMap<>(); public static SettlementHandler getHandler(SettlementBusiType busiType) { return allHandlerMap.get(busiType); } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { Map<String, SettlementHandler> map = applicationContext.getBeansOfType(SettlementHandler.class); map.values().forEach(e -> allHandlerMap.put(e.getBusiType(), e)); } } @SpringBootTest class Demo2023ApplicationTests { @Test void contextLoads() { // 收到结算结果通知,根据业务种类进行结算处理 SettlementHandler handler = DefaultSettlementHandler.getHandler(SettlementBusiType.RE1011); if (null != handler) { handler.handle(); } } }