• 设计模式之策略模式(场景说明)


    业务场景

            假设有这样的业务场景,大数据系统把文件推送过来,根据不同类型采取不同的解析方式。多数的小伙伴就会写出以下的代码:

    1. if(type=="A"){
    2. //按照A格式解析
    3. }else if(type=="B"){
    4. //按B格式解析
    5. }else{
    6. //按照默认格式解析
    7. }

    这个代码可能会存在哪些问题呢

    • 如果分支变多,这里的代码就会变得臃肿,难以维护,可读性低
    • 如果你需要接入一种新的解析类型,那只能在原有代码上修改

    说得专业一点的话,就是以上代码,违背了面向对象编程开闭原则以及单一原则

    • 开闭原则(对于扩展是开放的,但是对于修改是封闭的):增加或者删除某个逻辑,都需要修改到原来代码
    • 单一原则(规定一个类应该只有一个发生变化的原因):修改任何类型的分支逻辑代码,都需要改动当前类的代码。

    如果你的代码就是酱紫:有多个if...else等条件分支,并且每个条件分支,可以封装起来替换的,我们就可以使用策略模式来优化。

    策略模式定义

            策略模式定义了算法族,分别封装起来,让它们之间可以相互替换,此模式让算法的变化独立于使用算法的的客户。

            策略模式针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换。

    策略模式使用步骤

    策略模式怎么使用呢?酱紫实现的:

    1. 一个接口或者抽象类,里面两个方法(一个方法用于匹配类型,一个可替换的逻辑实现方法)
    2. 不同策略的差异化实现(就是说,不同策略的实现类)
    3. 具体上下文context来使用策略模式

    举例如下

    1. 一个接口,两个方法
      1. public interface IFileStrategy {
      2. //属于哪种文件解析类型
      3. FileTypeResolveEnum gainFileType();
      4. //封装的公用算法(具体的解析方法)
      5. void resolve(Object objectparam);
      6. }
    2. 不同策略的差异化实现 
    1. //A 类型策略具体实现
    2. @Component
    3. public class AFileResolve implements IFileStrategy {
    4. @Override
    5. public FileTypeResolveEnum gainFileType() {
    6. return FileTypeResolveEnum.File_A_RESOLVE;
    7. }
    8. @Override
    9. public void resolve(Object objectparam) {
    10. logger.info("A 类型解析文件,参数:{}",objectparam);
    11. //A类型解析具体逻辑
    12. }
    13. }
    14. //B 类型策略具体实现
    15. @Component
    16. public class BFileResolve implements IFileStrategy {
    17. @Override
    18. public FileTypeResolveEnum gainFileType() {
    19. return FileTypeResolveEnum.File_B_RESOLVE;
    20. }
    21. @Override
    22. public void resolve(Object objectparam) {
    23. logger.info("B 类型解析文件,参数:{}",objectparam);
    24. //B类型解析具体逻辑
    25. }
    26. }
    27. //默认类型策略具体实现
    28. @Component
    29. public class DefaultFileResolve implements IFileStrategy {
    30. @Override
    31. public FileTypeResolveEnum gainFileType() {
    32. return FileTypeResolveEnum.File_DEFAULT_RESOLVE;
    33. }
    34. @Override
    35. public void resolve(Object objectparam) {
    36. logger.info("默认类型解析文件,参数:{}",objectparam);
    37. //默认类型解析具体逻辑
    38. }
    39. }

    3. 使用策略模式

    如何使用呢?我们可以借助spring的生命周期,使用ApplicationContextAware接口,把对用的策略,初始化到map里面。然后对外提供resolveFile方法即可。 

    使用StrategyUseService#resolveFile方法即可。

    1. @Component
    2. public class StrategyUseService implements ApplicationContextAware{
    3. private Map<FileTypeResolveEnum, IFileStrategy> iFileStrategyMap = new ConcurrentHashMap<>();
    4. public void resolveFile(FileTypeResolveEnum fileTypeResolveEnum, Object objectParam) {
    5. IFileStrategy iFileStrategy = iFileStrategyMap.get(fileTypeResolveEnum);
    6. if (iFileStrategy != null) {
    7. iFileStrategy.resolve(objectParam);
    8. }
    9. }
    10. //把不同策略放到map
    11. @Override
    12. public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    13. Map<String, IFileStrategy> tmepMap = applicationContext.getBeansOfType(IFileStrategy.class);
    14. tmepMap.values().forEach(strategyService -> iFileStrategyMap.put(strategyService.gainFileType(), strategyService));
    15. }
    16. }
  • 相关阅读:
    R语言使用sample函数从dataframe中抽样指定个数的数据行、并配置是否有放回抽样(Random samples)
    Python学习之——文件操作
    认识并安装WSL
    Java IO之网络的简介说明
    Idea显示无法自动装配。找不到‘ xxx’类型的Bean
    什么是mvcc,mysql中的mvcc是怎么实现的
    切记:Python迭代器只可以读取一次,忽略会有意想不到的麻烦。
    一台机器下,多个Java版本的粗放与精细管理
    干货!用于多模态深度图超分辨率的离散余弦变换网络
    springboot 线程池参数解释
  • 原文地址:https://blog.csdn.net/CoderTnT/article/details/126709209