• 设计模式:策略模式


    我们玩游戏会有策略游戏,设计模式也会有策略模式。最开始接触策略模式的使用场景,是关于校验,针对不同的业务要进行不同的校验。同样的场景:优惠券折扣,不同渠道的信息发布等。

    Strategy Design Pattern,以下是GoF(是指提出和总结软件设计模式写成一本书的四个人)里面的定义:

    Define a family of algorithms, encapsulate each one, and make them
    interchangeable. Strategy lets the algorithm vary independently from
    clients that use it.

    定义一堆算法,然后让客户端根据策略去选择对应的算法。

    同理,策略模式也是行为型设计模式,重在使用的方面,同理对比的是工厂模式和观察者模式,这俩一个是创建型设计模式,一个是结构型设计模式,局限性也就体现出来了。工厂模式重在是解耦对象创建和使用,观察者是解耦观察者合被观察者,在结构上不让这俩“黏在一起”。策略模式则是,创建,使用,定义,结构上都给解耦了。(大多数的行为型的都这样,这也就是行为型设计模式用的比较多,你创建型,你就是个创建类的,结构型,你不结构上分开实际上也可以用,行为型则是奔着使用去的)。

    这里还是按照小争哥的三部分来看,就是策略模式的定义,创建,使用这三部分。

    策略的定义

    结构很简单:策略的接口,一堆对应策略接口的实现类

    
    public interface Strategy {
      void algorithmInterface();
    }
    
    public class ConcreteStrategyA implements Strategy {
      @Override
      public void  algorithmInterface() {
        //具体的算法...
      }
    }
    
    public class ConcreteStrategyB implements Strategy {
      @Override
      public void  algorithmInterface() {
        //具体的算法...
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    策略的创建

    对应的策略要一个type,这样什么类型下你要用什么类型的策略根据type就可以。下面是根据静态工厂,实际还可以建一个Map或者通过spring注入的方式直接给类型。

    
    public class StrategyFactory {
      private static final Map 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);
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    如果策略类是有状态的,根据业务场景的需要,我们希望每次从工厂方法中,获得的都是新创建的策略对象,而不是缓存好可共享的策略对象,那我们就需要按照如下方式来实现策略工厂类。(也就是if-else,但是这也可以根据况优化,map读表也可以解决)

    策略的使用

    这时候两种情况一个是我们知道一开始哪个类型策略,比如叔短信的消息发送,我们肯定要用短信的策略。
    有的是不知道什么策略,比如客户下单可以各种场景下,优惠券,折扣券,甚至是联系业务员改价,这种也叫做运行时动态。

    
    // 策略接口:EvictionStrategy
    // 策略类:LruEvictionStrategy、FifoEvictionStrategy、LfuEvictionStrategy...
    // 策略工厂:EvictionStrategyFactory
    
    public class UserCache {
      private Map cacheData = new HashMap<>();
      private EvictionStrategy eviction;
    
      public UserCache(EvictionStrategy eviction) {
        this.eviction = eviction;
      }
    
      //...
    }
    
    // 运行时动态确定,根据配置文件的配置决定使用哪种策略
    public class Application {
      public static void main(String[] args) throws Exception {
        EvictionStrategy evictionStrategy = null;
        Properties props = new Properties();
        props.load(new FileInputStream("./config.properties"));
        String type = props.getProperty("eviction_type");
        evictionStrategy = EvictionStrategyFactory.getEvictionStrategy(type);
        UserCache userCache = new UserCache(evictionStrategy);
        //...
      }
    }
    
    // 非运行时动态确定,在代码中指定使用哪种策略
    public class Application {
      public static void main(String[] args) {
        //...
        EvictionStrategy evictionStrategy = new LruEvictionStrategy();
        UserCache userCache = new UserCache(evictionStrategy);
        //...
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    实现一个支持给不同大小文件排序的小程序

    这个我还真实现过,只不过是linux环境下,对应的文件只用log文件和excel文件,就是写一个脚本指定这两个类型的linux脚本,但是我用的是命令来获取的。
    他这个要求就有一点变态,就是大小要自己算:

    假设有这样一个需求,希望写一个小程序,实现对一个文件进行排序的功能。文件中只包含整型数,并且,相邻的数字通过逗号来区隔。如果由你来编写这样一个小程序,你会如何来实现呢?你可以把它当作面试题,先自己思考一下,再来看我下面的讲解

    这里有一个初稿:

    
    public class Sorter {
      private static final long GB = 1000 * 1000 * 1000;
    
      public void sortFile(String filePath) {
        // 省略校验逻辑
        File file = new File(filePath);
        long fileSize = file.length();
        if (fileSize < 6 * GB) { // [0, 6GB)
          quickSort(filePath);
        } else if (fileSize < 10 * GB) { // [6GB, 10GB)
          externalSort(filePath);
        } else if (fileSize < 100 * GB) { // [10GB, 100GB)
          concurrentExternalSort(filePath);
        } else { // [100GB, ~)
          mapreduceSort(filePath);
        }
      }
    
      private void quickSort(String filePath) {
        // 快速排序
      }
    
      private void externalSort(String filePath) {
        // 外部排序
      }
    
      private void concurrentExternalSort(String filePath) {
        // 多线程外部排序
      }
    
      private void mapreduceSort(String filePath) {
        // 利用MapReduce多机排序
      }
    }
    
    public class SortingTool {
      public static void main(String[] args) {
        Sorter sorter = new Sorter();
        sorter.sortFile(args[0]);
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    结构拆分,方便后面的排序方法扩展

    
    public interface ISortAlg {
      void sort(String filePath);
    }
    
    public class QuickSort implements ISortAlg {
      @Override
      public void sort(String filePath) {
        //...
      }
    }
    
    public class ExternalSort implements ISortAlg {
      @Override
      public void sort(String filePath) {
        //...
      }
    }
    
    public class ConcurrentExternalSort implements ISortAlg {
      @Override
      public void sort(String filePath) {
        //...
      }
    }
    
    public class MapReduceSort implements ISortAlg {
      @Override
      public void sort(String filePath) {
        //...
      }
    }
    
    public class Sorter {
      private static final long GB = 1000 * 1000 * 1000;
    
      public void sortFile(String filePath) {
        // 省略校验逻辑
        File file = new File(filePath);
        long fileSize = file.length();
        ISortAlg sortAlg;
        if (fileSize < 6 * GB) { // [0, 6GB)
          sortAlg = new QuickSort();
        } else if (fileSize < 10 * GB) { // [6GB, 10GB)
          sortAlg = new ExternalSort();
        } else if (fileSize < 100 * GB) { // [10GB, 100GB)
          sortAlg = new ConcurrentExternalSort();
        } else { // [100GB, ~)
          sortAlg = new MapReduceSort();
        }
        sortAlg.sort(filePath);
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53

    静态工厂优化后

    
    public class SortAlgFactory {
      private static final Map 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);
      }
    }
    
    public class Sorter {
      private static final long GB = 1000 * 1000 * 1000;
    
      public void sortFile(String filePath) {
        // 省略校验逻辑
        File file = new File(filePath);
        long fileSize = file.length();
        ISortAlg sortAlg;
        if (fileSize < 6 * GB) { // [0, 6GB)
          sortAlg = SortAlgFactory.getSortAlg("QuickSort");
        } else if (fileSize < 10 * GB) { // [6GB, 10GB)
          sortAlg = SortAlgFactory.getSortAlg("ExternalSort");
        } else if (fileSize < 100 * GB) { // [10GB, 100GB)
          sortAlg = SortAlgFactory.getSortAlg("ConcurrentExternalSort");
        } else { // [100GB, ~)
          sortAlg = SortAlgFactory.getSortAlg("MapReduceSort");
        }
        sortAlg.sort(filePath);
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    查表法优化

    
    public class Sorter {
      private static final long GB = 1000 * 1000 * 1000;
      private static final List 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;
        for (AlgRange algRange : algs) {
          if (algRange.inRange(fileSize)) {
            sortAlg = algRange.getAlg();
            break;
          }
        }
        sortAlg.sort(filePath);
      }
    
      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;
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
  • 相关阅读:
    uni——判断option传参
    Vue 卸载Better Scroll插件
    Java并发编程之ReentrantLock重入锁原理解析
    借助 ChatGPT 编写的 libbpf eBPF 工具开发实践教程: 通过例子学习 eBPF
    实例036:算素数
    HarmonyOS CPU与I/O密集型任务开发指导
    【Neo4j系列】Neo4j概念简介及整合SpringBoot
    MySQL表的增删改查--你都知道吗?
    Arcgis pro通过渔网工具生成规则采样点,并对栅格数据进行采样
    JS原生复制功能
  • 原文地址:https://blog.csdn.net/FeiChangWuRao/article/details/126583421