设计模式是面向对象编程中常用的方式,它都可以让我们的代码的扩展性、复用性以及可维护性更强。今天我们就来介绍一下如何以最优雅的方式使用策略模式
在之前的文章中,我们已经介绍过策略模式,具体可以参考这篇文章策略模式详解
/** * 支付 */public interface PayService { /** * pay */ void pay();}public class AliPayService implements PayService { /** * pay */ @Override public void pay() { }}public class UnionPayService implements PayService { /** * pay */ @Override public void pay() { }}public class WeChatPayService implements PayService { /** * pay */ @Override public void pay() { }}public class PayServiceFactory { private static final Map payServiceMap = new HashMap<>(); static { payServiceMap.put("weChatPay", new WeChatPayService()); payServiceMap.put("aliPay", new AliPayService()); payServiceMap.put("union", new UnionPayService()); } public static PayService getPayService(String name) { return payServiceMap.get(name); }}public class PayFactoryDemo { public static void main(String[] args) { PayService payService = PayServiceFactory.getPayService("aliPay"); payService.pay(); }} 通过上面的代码,我们知道策略模式可以和工厂模式结合起来使用,这样,我们便可以通过名称直接选择不同的策略,这样看起来还是比较完美的,但是,这里面还是存在一些问题
/** * 支付 */public interface PayService { /** * pay */ void pay();}public abstract class BasePayService implements PayService { @PostConstruct public void init() { PayServiceFactory.putPayService(this.name(), this); } /** * 策略名称 * * @return */ protected abstract String name();}@Componentpublic class AliPayService extends BasePayService { /** * pay */ @Override public void pay() { } /** * 策略名称 * * @return */ @Override protected String name() { return "aliPay"; }}@Componentpublic class UnionPayService extends BasePayService { /** * pay */ @Override public void pay() { } /** * 策略名称 * * @return */ @Override protected String name() { return "union"; }}@Componentpublic class WeChatPayService extends BasePayService { /** * pay */ @Override public void pay() { } /** * 策略名称 * * @return */ @Override protected String name() { return "weChatPay"; }}public class PayServiceFactory { private static final Map payServiceMap = new ConcurrentHashMap<>(); public static PayService getPayService(String name) { return payServiceMap.get(name); } public static void putPayService(String name, PayService payService) { payServiceMap.put(name, payService); }}public class PayFactoryDemo { public static void main(String[] args) { PayService payService = PayServiceFactory.getPayService("aliPay"); payService.pay(); }} 通过上面的示例代码,我们完美的将策略模式,工厂模式和spring想结合,每次在bean初始化的时候就会执行被PostConstruct注解标注的方法,这样,就会将策略自动添加到工厂中,这就完美的解决了每次增加策略都需要更改策略工厂的问题,这样看起来已经很完美了吧?事实真的是这样吗?
当策略的实现类被定义成懒加载时,我们在获取策略的时候就会出现问题,因为这个时候,我们没有直接使用策略的实现类,这样策略就没有初始化,就不会被添加到策略工厂,我们在使用的时候就会出现找不到策略的问题
解决方式:在策略bean上添加@Lazy(false),让spring在启动的时候就加载bean,而不是使用懒加载,但是这也依旧存在浪费启动时间,浪费内存的问题
/** * 支付 */public interface PayService extends IResolver { /** * pay */ void pay();}public class AliPayService implements PayService { /** * pay */ @Override public void pay() { } /** * 注册器中的查找名称 * * @return */ @Override public String getKey() { return "aliPay"; }}public class UnionPayService implements PayService { /** * pay */ @Override public void pay() { } /** * 注册器中的查找名称 * * @return */ @Override public String getKey() { return "union"; }}public class WeChatPayService implements PayService { /** * pay */ @Override public void pay() { } /** * 注册器中的查找名称 * * @return */ @Override public String getKey() { return "weChatPay"; }}public class PayServiceRegistry extends AbstractResolverRegistry { /** * 注册器容器的类型 * * @return */ @Override protected Class getResolverClass() { return PayService.class; } /** * 获取默认处理器 * * @return */ @Override protected String getDefaultKey() { return "aliPay"; }}public class PayFactoryDemo { public static void main(String[] args) { ApplicationContext applicationContext = new AnnotationConfigApplicationContext(); PayServiceRegistry payServiceRegistry = applicationContext.getBean(PayServiceRegistry.class); PayService payService = payServiceRegistry.getResolver("aliPay"); payService.pay(); }}/** * 解析器 * */public interface IResolver { /** * 注册器中的查找名称 * * @return */ public K getKey();}/** * 同类型解析器抽象类 */@Slf4jpublic abstract class AbstractResolverRegistry> implements ApplicationContextAware { private Map resolverMap = new HashMap<>(); private ApplicationContext ctx; public V getResolver(K k1) { return Optional.ofNullable(resolverMap.get(k1)).orElse(resolverMap.get(getDefaultKey())); } @SuppressWarnings("unchecked") @PostConstruct private void init() { Class clazz = getResolverClass(); Collection list = ctx.getBeansOfType(clazz).values(); if (list != null) { list.forEach((v1) -> { if (v1.getKey() instanceof String) { String str = (String) v1.getKey(); if (StringUtils.isEmpty(str)) { log.warn("配置为空,采用默认处理器:{},处理器类:{}", null, v1); resolverMap.put(v1.getKey(), v1); } else { List strs = Arrays.asList(str.split(",")); for (String v : strs) { log.info("处理器code:{},处理器类:{}", v, v1); resolverMap.put((K) v, v1); } } } else { if (v1.getKey() == null) { log.info("配置为空,采用默认处理器:,处理器类:{}", v1); } else { log.info("非String类型的,业务处理器code:{},处理器类:{}", v1.getKey(), v1); } resolverMap.put(v1.getKey(), v1); } }); } log.info("初始化classType={},resolverRegistry.length={}", new Object[]{clazz, list != null ? list.size() : 0}); } /** * 注册器容器的类型 * * @return */ protected abstract Class getResolverClass(); /** * @see ApplicationContextAware#setApplicationContext(ApplicationContext) */ @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.ctx = applicationContext; } /** * 获取默认处理器 * * @return */ protected abstract K getDefaultKey();} 在上面的例子中,我们将工厂定义在了Spring Bean中,通过这种形式,我们完美的解决了懒加载的问题,即使策略Bean采用的是懒加载,也依旧没有问题
模板模式和策略模式的主体结构是一样的,因此,模板模式也可以用这个方式来实践最佳策略
| 留言与评论(共有 0 条评论) “” |