news 2026/11/3 9:13:36

【设计模式之美】策略模式实践:不同大小(采用不同的策略)文件进行排序

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【设计模式之美】策略模式实践:不同大小(采用不同的策略)文件进行排序

文章目录

  • 一. 问题与解决思路
  • 二. 代码实现与分析
    • 1. 业务代码逻辑的架子
    • 2. 代码重构:使用策略模式来解耦代码逻辑
  • 三. 进一步:满足开闭原则:使用注解或配置文件

设计原则和思想其实比设计模式更加普适和重要,掌握了代码的设计原则和思想,我们甚至可以自己创造出来新的设计模式。—《设计模式之美》王争

一. 问题与解决思路

假设有这样一个需求,希望写一个小程序,实现对一个文件进行排序的功能。如果文件涉及到的文件有不同规模的,如下

  • 10GB 大小,因为内存有限(比如只有 8GB 大小),我们没办法一次性加载文件中的所有数据到内存中,这个时候,我们就要利用外部排序算法(ing)了。
  • 100GB 大小,我们为了利用 CPU 多核的优势,可以在外部排序的基础之上进行优化,加入多线程并发排序的功能,这就有点类似“单机版”的 MapReduce。
  • 1TB 大小,即便是单机多线程排序,这也算很慢了。这个时候,我们可以使用真正的 MapReduce 框架,利用多机的处理能力,提高排序的效率。

很明显不同大小的文件需要使用不同的算法逻辑去实现,而不同的算法逻辑就可以使用策略模式将算法逻辑解耦,具体算法实现不是本文的重点,我们来看下策略模式是如何实现这个代码架构的。

二. 代码实现与分析

1. 业务代码逻辑的架子

如下逻辑架子,简单实现了算法的一些流程步骤,具体算法暂时不实现。

publicclassSorter{privatestaticfinallongGB=1000*1000*1000;publicvoidsortFile(StringfilePath){// 省略校验逻辑Filefile=newFile(filePath);longfileSize=file.length();if(fileSize<6*GB){// [0, 6GB)quickSort(filePath);}elseif(fileSize<10*GB){// [6GB, 10GB)externalSort(filePath);}elseif(fileSize<100*GB){// [10GB, 100GB)concurrentExternalSort(filePath);}else{// [100GB, ~)mapreduceSort(filePath);}}privatevoidquickSort(StringfilePath){// 快速排序}privatevoidexternalSort(StringfilePath){// 外部排序}privatevoidconcurrentExternalSort(StringfilePath){// 多线程外部排序}privatevoidmapreduceSort(StringfilePath){// 利用MapReduce多机排序}}publicclassSortingTool{publicstaticvoidmain(String[]args){Sortersorter=newSorter();sorter.sortFile(args[0]);}}

2. 代码重构:使用策略模式来解耦代码逻辑

分析下需求和代码结构:

  • 策略定义与创建: 每种排序类都是无状态的,我们没必要在每次使用的时候,都重新创建一个新的对象。所以,我们可以使用工厂模式对对象的创建进行封装。
  • 策略的使用:这里的 if-else 逻辑分支不多、也不复杂,这样写完全没问题。当然你也可以使用查表法

接下来我们分别实现这几个方面

策略定义:

publicinterfaceISortAlg{voidsort(StringfilePath);}publicclassQuickSortimplementsISortAlg{@Overridepublicvoidsort(StringfilePath){//...}}...ExternalSortimplementsISortAlgConcurrentExternalSortimplementsISortAlgMapReduceSortimplementsISortAlg...

策略实现:

publicclassSortAlgFactory{privatestaticfinalMap<String,ISortAlg>algs=newHashMap<>();static{algs.put("QuickSort",newQuickSort());algs.put("ExternalSort",newExternalSort());algs.put("ConcurrentExternalSort",newConcurrentExternalSort());algs.put("MapReduceSort",newMapReduceSort());}publicstaticISortAlggetSortAlg(Stringtype){if(type==null||type.isEmpty()){thrownewIllegalArgumentException("type should not be empty.");}returnalgs.get(type);}}。。。}

策略使用:

publicclassSorter{privatestaticfinallongGB=1000*1000*1000;privatestaticfinalList<AlgRange>algs=newArrayList<>();static{algs.add(newAlgRange(0,6*GB,SortAlgFactory.getSortAlg("QuickSort")));algs.add(newAlgRange(6*GB,10*GB,SortAlgFactory.getSortAlg("ExternalSort")));algs.add(newAlgRange(10*GB,100*GB,SortAlgFactory.getSortAlg("ConcurrentExternalSort")));algs.add(newAlgRange(100*GB,Long.MAX_VALUE,SortAlgFactory.getSortAlg("MapReduceSort")));}publicvoidsortFile(StringfilePath){// 省略校验逻辑Filefile=newFile(filePath);longfileSize=file.length();ISortAlgsortAlg=null;for(AlgRangealgRange:algs){//如果处于某一个范围就选定这个,并结束循环if(algRange.inRange(fileSize)){sortAlg=algRange.getAlg();break;}}sortAlg.sort(filePath);}privatestaticclassAlgRange{privatelongstart;privatelongend;//AlgRange封装策略类与策略类型,这样就能去除if elseprivateISortAlgalg;publicAlgRange(longstart,longend,ISortAlgalg){this.start=start;this.end=end;this.alg=alg;}publicISortAlggetAlg(){returnalg;}publicbooleaninRange(longsize){returnsize>=start&&size<end;}}}

三. 进一步:满足开闭原则:使用注解或配置文件

即便这样,当我们添加新的排序算法的时候,还是需要修改策略实现与选择的代码,并不完全符合开闭原则。

有什么办法让我们完全满足开闭原则呢?

对于 Java 语言来说,我们可以通过反射来避免对策略工厂类的修改。具体是这么做的:

  1. 我们通过一个配置文件或者自定义的 annotation 来标注都有哪些策略类;策略工厂类读取配置文件或者搜索被 annotation 标注的策略类,然后通过反射动态地加载这些策略类、创建策略对象;
  2. 当我们新添加一个策略的时候,只需要将这个新添加的策略类添加到配置文件或者用 annotation 标注即可。

当添加新的排序算法时,我们只需要改动配置文件即可,不需要改动代码。




参考:《设计模式之美》–王争

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/11/3 9:13:29

【高等数学】第三章知识点(1)一元函数积分学:不定积分

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/11/3 9:13:23

【python虚拟环境管理【二】】【mac m3】使用conda管理python项目

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/11/3 9:12:21

数据湖概述:大数据演进阶段-数据湖

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/11/3 9:10:49

【运维】hadoop3.0.3集群安装(一)多节点安装

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华