策略模式的最佳实践方式

背景

设计模式是面向对象编程中常用的方式,它都可以让我们的代码的扩展性、复用性以及可维护性更强。今天我们就来介绍一下如何以最优雅的方式使用策略模式

策略模式详解

在之前的文章中,我们已经介绍过策略模式,具体可以参考这篇文章策略模式详解

策略模式实践方式

和工厂模式结合使用

/** * 支付 */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();    }}

通过上面的代码,我们知道策略模式可以和工厂模式结合起来使用,这样,我们便可以通过名称直接选择不同的策略,这样看起来还是比较完美的,但是,这里面还是存在一些问题

  • 每次增加策略还需要更改工厂,不符合开闭原则(虽然改动很小)
  • 没有和spring结合起来使用

结合spring定义静态工厂

/** * 支付 */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,而不是使用懒加载,但是这也依旧存在浪费启动时间,浪费内存的问题

通过单独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 条评论) “”
   
验证码:

相关文章

推荐文章