美文网首页
8 策略模式-行为模式

8 策略模式-行为模式

作者: 格林哈 | 来源:发表于2023-02-07 11:19 被阅读0次

    一、原理与实现

    1. 定义

    • 定义一族算法类,将每个算法分别封装起来,让它们可以互相替换。策略模式可以使算法的变化独立于使用它们的客户端(这里的客户端代指使用算法的代码)。

      • 使用策略模式可以将算法的定义与使用隔离开来,保证类的单一职责原则,使得程序整体符合开闭原则。
    • 解耦对象

      • 工厂模式是解耦对象的创建和使用,
      • 观察者模式是解耦观察者和被观察者
      • 它解耦的是策略的定义、创建、使用这三部分

    2. 策略定义

    • 包含一个策略接口和一组实现这个接口的策略类。因为所有的策略类都实现相同的接口,所以,客户端代码基于接口而非实现编程,可以灵活地替换不同的策略。

    二、实践

    • 结合spring 容器

    1. 简单工厂

    public interface GenericInterface<E> {
         E getType();
    }
    
    @Slf4j
    public class HandlerFactory<E, T extends GenericInterface<E>> implements InitializingBean, ApplicationContextAware {
        private ApplicationContext applicationContext;
        /**
         * 泛型策略接口类型
         */
        private Class<T> strategyInterfaceType;
    
        /**
         * java泛型只存在于编译期,无法通过例如T.class的方式在运行时获取其类信息
         * 因此利用构造函数传入具体的策略类型class对象为getBeansOfType()方法
         * 提供参数
         *
         * @param strategyInterfaceType 要传入的策略接口类型
         */
        public HandlerFactory(Class<T> strategyInterfaceType) {
            this.strategyInterfaceType = strategyInterfaceType;
        }
        /**
         * 策略实例容器
         */
        private Map<E, T> GET_SHOP_RANK_STRATEGY_MAP;
        /**
         * 根据不同参数类型获取对应的接口实现类
         *
         * @param type 参数类型
         * @return 参数类型对应的接口实现类
         */
        public T getStrategy(E type) {
            return GET_SHOP_RANK_STRATEGY_MAP.get(type);
        }
    
        @Override
        public void afterPropertiesSet() {
            Map<String, T> beansOfType = applicationContext.getBeansOfType(strategyInterfaceType);
            log.info("afterPropertiesSet beansOfType={}", JsonUtil.dumps(beansOfType));
    
            GET_SHOP_RANK_STRATEGY_MAP = Optional.ofNullable(beansOfType)
                    .map(beansOfTypeMap -> beansOfTypeMap.values().stream()
                            .filter(strategy -> StringUtils.isNotEmpty(strategy.getType().toString()))
                            .collect(Collectors.toMap(strategy -> strategy.getType(), Function.identity())))
                    .orElse(new HashMap<>(8));
            log.info("afterPropertiesSet GET_SHOP_RANK_STRATEGY_MAP={}", JsonUtil.dumps(GET_SHOP_RANK_STRATEGY_MAP) );
        }
    
        @Override
        public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
            this.applicationContext = applicationContext;
        }
    }
    

    2. 业务场景

    • 一个项目要支持很多游戏, 每个游戏的开始游戏,和结束游戏都是一样的。
    1. 策略接口
    public interface GameCommonStrategyInterface extends GenericInterface<Long> {
    
        /**
         * 开始游戏
         * @param gameId
         * @param userId
         * @param lang
         * @return
         */
         GameStartDTO gameStart(Long gameId, long userId, String lang) ;
    
        /**
         * 结束游戏
         * @param gameOver
         * @param userId
         * @param lang
         * @return
         */
         GameResultDTO gameOver(GameOverDTO gameOver, long userId, String lang);
    }
    
    
    1. 策略工厂注册
    @Configuration
    public class BeanFactoryConfig {
        @Bean
        public HandlerFactory<Long, GameCommonStrategyInterface> gameCommonStrategyInterface(){
            return new HandlerFactory<>(GameCommonStrategyInterface.class);
        }
    
    
    
    }
    
    1. 某一个游戏的具体策略
      • type 是一个long 类型的id
    @Component
    public class SheepGameCommonStrategy implements GameCommonStrategyInterface {
    
    
        @Override
        public GameStartDTO gameStart(Long gameId, long userId, String lang) {
            ...
        }
    
        @Override
        public GameResultDTO gameOver(GameOverDTO gameOver, long userId, String lang) {
           ...
        }
    
        @Override
        public Long getType() {
            return 1L;
        }
    }
    
    

    2.1 总结

    • 优点
      • 将策略接口类型参数化,策略工厂不受接口类型限制,成为任意接口的策略工厂。

    相关文章

      网友评论

          本文标题:8 策略模式-行为模式

          本文链接:https://www.haomeiwen.com/subject/engxkdtx.html