美文网首页
策略模式

策略模式

作者: lj72808up | 来源:发表于2021-04-25 11:53 被阅读0次

    1. 什么是策略模式

    • 定义一个算法簇, 将每个算法封装起来, 让他们可以相互替换; 并让算法的变化独立于调用算法的一方.
    • 策略模式: 将算法的定义, 创建, 使用三方解耦

    2. 解耦三方

    1. 策略(算法)的定义

    策略模式中, 强调的事一组算法可以相互替换. 因此, 策略是接口的一组实现

     //  策略. 算法的接口
     public interface Strategy {
       void algorithmInterface();
     }
    
     public class ConcreteStrategyA implements Strategy {
       @Override
       public void  algorithmInterface() {
         //具体的算法...
       }
     }
    
     public class ConcreteStrategyB implements Strategy {
       @Override
       public void  algorithmInterface() {
         //具体的算法...
       }
     }
    

    2. 策略的创建

    所谓策略的创建, 就是根据不同情况, 选择不同算法(策略)进行调用. 可以使用工厂类创建算法(策略)对象. 这里需要注意的是, 策略分为有状态和无状态的

    • 无状态类策略:
      不包含成员变量, 只有纯粹的算法实现. 这种情况不需要每次调用新建算法对象, 可以预先创建好缓存在工厂类中
      public class StrategyFactory {
        private static final Map<String, Strategy> strategies = new HashMap<>();
    
        static {
          strategies.put("A", new ConcreteStrategyA());
          strategies.put("B", new ConcreteStrategyB());
        }
    
        public static Strategy getStrategy(String type) {
          if (type == null || type.isEmpty()) {
            throw new IllegalArgumentException("type should not be empty.");
          }
          return strategies.get(type);
        }
      }
    
    • 有状态类策略:
      • 什么是有状态的策略
        包含成员变量, 每次调用策略对象需要新建, 因此不能把策略对象需要在工厂模式的 get 方法中新建. (这里用 ConcreteStrategyA 和 ConcreteStrategyB 模拟)
          public class StrategyFactory {
            public static Strategy getStrategy(String type) {
              // 出现大量 if-else 判断代码. 而策略模式是可以消除这种大量判断代码的, 具体做法如下
              if (type == null || type.isEmpty()) {
                throw new IllegalArgumentException("type should not be empty.");
              }
        
              if (type.equals("A")) {
                return new ConcreteStrategyA();
              } else if (type.equals("B")) {
                return new ConcreteStrategyB();
              }
        
              return null;
            }
          }
        

    3. 用 for 消除大量的 if-else 判断使用哪种策略的逻辑

    我们看到, 当策略对象不能简单的通过查表法从工厂类中获取时, 工厂类的 getStrategy() 就会出现大量的判断逻辑. 这种实现方式相当于把原来的 if-else 分支逻辑,从调用方转移到策略的创建方.
    比如, 有一个需求: 对文件排序. 但根据文件大小的不同, 会选择内存排序, 多线程的外排序, mapreduce 排序这3个不同算法. 策略的选取已经不是简单的类型判断了, 怎么避免 if-else 的出现呢 ?

    • 如下给出了解决办法: 将策略和满足策略调用的条件封装到一起, 用 for 循环判断哪个策略的调用成立, 然后获取策略对象
    interface ISortAlg {
        void sort(String filePath);
    }
    
    class QuickSort implements ISortAlg {
        @Override
        public void sort(String filePath) {
            //...
        }
    }
    
    class ExternalSort implements ISortAlg {
        @Override
        public void sort(String filePath) {
            //...
        }
    }
    
    class ConcurrentExternalSort implements ISortAlg {
        @Override
        public void sort(String filePath) {
            //...
        }
    }
    
    class MapReduceSort implements ISortAlg {
        @Override
        public void sort(String filePath) {
            //...
        }
    }
    
    class SortAlgFactory {
        private static final Map<String, ISortAlg> algs = new HashMap<>();
    
        static {
            algs.put("QuickSort", new QuickSort());
            algs.put("ExternalSort", new ExternalSort());
            algs.put("ConcurrentExternalSort", new ConcurrentExternalSort());
            algs.put("MapReduceSort", new MapReduceSort());
        }
    
        public static ISortAlg getSortAlg(String type) {
            if (type == null || type.isEmpty()) {
                throw new IllegalArgumentException("type should not be empty.");
            }
            return algs.get(type);
        }
    }
    
    class Sorter {
        private static final long GB = 1000 * 1000 * 1000;
        private static final List<AlgRange> algs = new ArrayList<>();
        static {
            algs.add(new AlgRange(0, 6*GB, SortAlgFactory.getSortAlg("QuickSort")));
            algs.add(new AlgRange(6*GB, 10*GB, SortAlgFactory.getSortAlg("ExternalSort")));
            algs.add(new AlgRange(10*GB, 100*GB, SortAlgFactory.getSortAlg("ConcurrentExternalSort")));
            algs.add(new AlgRange(100*GB, Long.MAX_VALUE, SortAlgFactory.getSortAlg("MapReduceSort")));
        }
    
        public void sortFile(String filePath) {
            File file = new File(filePath);
            long fileSize = file.length();
            ISortAlg sortAlg = null;
            /** 原先的 if-else 判断, 改成 for 遍历每个策略, 判断策略调用条件是否成立 */
            for (AlgRange algRange : algs) {
                if (algRange.inRange(fileSize)) {
                    sortAlg = algRange.getAlg();
                    break;
                }
            }
            sortAlg.sort(filePath);
        }
    
        /** Algorithm 范围, 封装策略和策略调用的条件 */
        private static class AlgRange {
            private long start;
            private long end;
            private ISortAlg alg;
    
            public AlgRange(long start, long end, ISortAlg alg) {
                this.start = start;
                this.end = end;
                this.alg = alg;
            }
    
            public ISortAlg getAlg() {
                return alg;
            }
    
            // 判断文件大小是否在范围内
            public boolean inRange(long size) {
                return size >= start && size < end;
            }
        }
    }
    

    相关文章

      网友评论

          本文标题:策略模式

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