`

策略模式引发的一些思考

阅读更多
一、前言
        在这里直言不讳,这篇博文是看了某位老师新出的一段Java SE视频中的一道作业题,题目很简单,要求用策略模式实现排序;其中有三个字段,需要对这个三个字段(ID,NAME,AGE)进行排序,并且还要求有升序和降序的方式。对此有兴趣的朋友可以在网上搜索获取,在此不做任何说明,避免7+7的厄运。
        也许是因为无聊吧,我做了这道简单不能再简单的题目。但是却给了我全新的思考感受,使我能够更有明确目的地在使用设计模式
        上面加粗的一句话貌似不好理解,太抽象,但又没有比这更能涵盖我所表达的意思了。换句话来说就是又增加了一条使用设计模式的心里暗示,即更有针对性地使用设计模式来解决应用场景中出现的问题。
        我用一个更容易理解的比喻来解释一下:应用场景好比是一道菜,设计模式就好比是做这道菜所用的调料,用设计模式解决应用场景的问题也就好比是不同调料搭配起来会让这道菜具有不同的口味。由此引发的一个官方言论,即不要过分依赖设计模式,就好比是盐放的太多了,心里就该咒骂“打死卖盐的”了。

二、寻找应用场景中隐藏的问题
        首先让我们来分析一下这道题目,题目要求很明确,就是排序。单拿这道题目作为应用场景,该应用场景中需要对三个字段进行排序;注意应用场景中的问题出现了
        1.不仅仅实现排序功能,并且还要实现升序和降序的排序方式,详细点地说就意味着要实现3*2个排序算法。
        2.应用场景中的三个字段在未来或许还会增加,并伴随着需要进行排序的可能性,也就是那个“3”会变化。
        3.应用场景中的排序方式也是会变化的,即使这个假设放在这个应用场景中不太合适,但是也能说明一些问题的,问题本质上没太大的区别。
        4.前三条是针对实现来说地,下面的几条针对可维护性层面来说。我之所以写出这篇博文,是因为我终于思考出设计模式对今后代码的维护也是有很大好处的。为什么说是“终于”?以往看过很多设计模式相关的书籍,里面也曾提到可维护性之类的话题;但是看了之后,也是能够理解,在解决实际问题的时候这些话题可就不翼而飞了,脑海里面只想着我要使用设计模式,而不是我该怎样使用设计模式。我在一番思考之后,对此类话题就很敏感了,换句话来说,选择使用哪种设计模式之前,又多了一条思考路径(前言也提到了这个话题)。
        5.结合上述4条,用第五条明确指出代码维护带来的问题。就本文的应用场景,它要实现3*2个排序算法,也就是说以后要维护6个算法;如果两个乘数都在不断的增长,那就要维护N*N个算法。为此需要用更优雅的方式来设计,解决今后对代码维护引发的超大工作量问题。

三、三种设计方案
        针对这个应用场景,我脑海里浮现出了三种设计方案。前两种方案是在没太理解策略模式之前经常用到的。后一种设计方案,看上去跟第二个很类似,但是却比前者更具内涵。下面是三种方案的方案以伪代码的方式介绍,就不放代码介绍了,一太占篇幅(好吧,我那是懒!),二此文最后提供第三种解决方案的源码。本文只阐述我思考后的成果,请勿沉浸在问题和代码表面上!
        1.不使用模式
  if (升序) {
			if (升序比较ID) {
				// 比较后的算法
			} else if (升序比较NAME) {
				// 比较后的算法
			} else if (升序比较AGE) {
				// 比较后的算法
			}
		} else if (降序) {
			if (降序比较ID) {
				// 比较后的算法
			} else if (降序比较NAME) {
				// 比较后的算法
			} else if (降序比较AGE) {
				// 比较后的算法
			}
		}
        这个设计可谓很老很糟糕,也算个懒人专用方式(好吧,我承认经常这么干,前提要保证这个需求是千年不变的)。这个设计需要维护6个算法,如果连把比较算法封成一个方法都不弄的话,那就会更悲剧了。请参见第二节第五条里的说明。
        2.不完整的策略模式
        鉴于上面那个悠久而又古老的设计,再来进一步的优化。
        //(1)定义6个实现自Comparator接口的排序算法实现类,有3个针对字段升序排序, 另外3个针对字段降序排序。
        //(2)调用Collection.sort(List,Comparator)方法针对List进行排序。
        实现Comparator接口也是在使用策略模式,具体参见本文最后的源码附件,同时引发的问题请参见第二节第五条里的说明。
这个设计方式看上去靠谱了很多,但是需要维护的算法(类)还是N*N。
        3.比较完整的策略模式
        那就继续优化,下面的三步思路足以说明,具体参见本文最后的源码附件。
       
//(1)定义1个排序方式接口(策略接口)。针对本文所引用的应用场景,该接口提供两个方法,分别对Integer和String类型字段做比较操作;该方法返回的是int类型。
 //(2)定义2个实现自先前定义的排序方式接口的实现类(具体策略),分别针对于正序和降序实现各自的算法。因该算法内部使用JDK提供的比较方法,其内部采用的是减法操作,故接口中的两个方法需返回int类型。
//(3)定义3个实现自Comparator接口的排序算法实现类(环境),分别针对三个字段的排序。每个类都分别保有先前定义的排序方式接口的引用,并且实现的方法中需调用该接口引用所提供的相应方法。
        特别要注意本节用阿拉伯数字表明的地方。这个设计与第二个设计同样也定义了6个算法类,表面上看是差不多的;不过这里使用了两次策略模式,使维护的算法(类)变为N+N。
        4.结论
        首先让我们来假设一下:现在需求有变化了,客户方又突然想增加100个字段,并且这新增的字段都需要提供可排序功能;第一种设计暂且不考虑,那就考虑后两种。针对这个新需求,两者的差别慢慢地浮现出来。
        请仔细看,第二种设计方式中的每个字段都需要有对应的且类似的2个类,并且应对这样的需求显然愈发无力了,因为维护数量是以乘积计算的;而第三种设计方案,连用了两个策略模式,其中一个是将排序方式和待排序的字段分离开来,使二者的变化不会互相影响对方,使代码维护量变为加法计算,明显比前者达到的效果要好得多。
这时客户方那边又提出了一个新需求,这次不是再加100个字段了,而仅仅是再要增加1个排序方式,如果换成第二种设计方案,是不是要抓狂了?
        此番思考之后,得出了这样一个结论:使用抽象的东西要尽可能得将其转换成实际的东西;理解一个实际的东西要尽可能得将其转换成抽象的东西。

四、总结
         本文的题目其实有些迷惑性,是说策略模式呢?还是在说思考呢?其实由策略模式引发的思考,不仅是对策略这个单个模式的思考,也是对整个设计模式的全面思考;现阶段的思考重心完全倾向于怎么更给力的使用,绝对的要有目的性的去用;还不会用?有了目的就很好办了,把这个模式的UML图找出来,再把场景问题往里套,就完全OK了。不过说实话,本文还是侧重于对思考后的阐述。
        有些幽默的是本文所引发的这个思考是我在不经意间摸索出来的,不过看起来还是很靠谱的,又为我提供了一个思考的路径(不思考永远不会有不经意)。
        因本文完全是我思考后的文字,也就是说是用我的思维方式来描述思考的过程,不见得您能读的明白;别着急,只要理解大致意思,用您的思维方式来理解就好了。看书也是同样的道理,用自己的思维方式去理解书中的内容,而不要一味地随着作者的思维方式;换句话说思维方式可以借鉴,但不要模仿。
        思考需从不同的角度无限延伸,定能有所收获。

0
4
分享到:
评论
2 楼 深夜未眠 2010-12-27  
紫轩侠客 写道
为什么不使用装饰器模式呢?

1.虽然有升序和降序之分,但算法实现不相同,用策略模式更为恰当。
2.策略模式改变的是内核,策略模式改变的是外壳;针对此问题使用策略模式更为恰当。话说回来,设计模式是来解决实际问题的,对于用哪个好,到没必要那么纠结的。
3.另外本文主要是说明在使用设计模式时,需从不同的角度去思考,即从可维护性来考虑,针对实际问题选择合适的设计模式,避免了无从下手的尴尬。
1 楼 紫轩侠客 2010-12-27  
为什么不使用装饰器模式呢?

相关推荐

    Java策略模式的使用(枚举策略与简单工厂策略)

    后端同学在开发过程中,势必会遇到多条件判断的情况,大部分时候都会直接采用if-else的形式去处理,这样的操作会存在不易扩展的问题,那么...对比枚举策略与简单工厂+策略模式的不同使用,抛砖引玉,引发你更多的思考

    UML和模式应用(架构师必备).part02.rar

    26.2 一些GRASP原则是对其他设计模式的归纳 26.3 设计中发现的“分析”:领域模型 26.4 工厂(Factory) 26.5 单实例类(GoF) 26.6 具有不同接口的外部服务问题的结论 26.7 策略(GoF) 26.8 组合(GoF)和...

    UML和模式应用(架构师必备).part06.rar

    26.2 一些GRASP原则是对其他设计模式的归纳 26.3 设计中发现的“分析”:领域模型 26.4 工厂(Factory) 26.5 单实例类(GoF) 26.6 具有不同接口的外部服务问题的结论 26.7 策略(GoF) 26.8 组合(GoF)和...

    asp.net知识库

    DbHelperV2 - Teddy的通用数据库访问组件设计和思考 也论该不该在项目中使用存储过程代替SQL语句 如何使数据库中的表更有弹性,更易于扩展 存储过程——天使还是魔鬼 如何获取MSSQLServer,Oracel,Access中的数据字典...

    UML和模式应用(架构师必备).part01.rar

    26.2 一些GRASP原则是对其他设计模式的归纳 26.3 设计中发现的“分析”:领域模型 26.4 工厂(Factory) 26.5 单实例类(GoF) 26.6 具有不同接口的外部服务问题的结论 26.7 策略(GoF) 26.8 组合(GoF)和...

    UML和模式应用(架构师必备).part07.rar

    26.2 一些GRASP原则是对其他设计模式的归纳 26.3 设计中发现的“分析”:领域模型 26.4 工厂(Factory) 26.5 单实例类(GoF) 26.6 具有不同接口的外部服务问题的结论 26.7 策略(GoF) 26.8 组合(GoF)和...

    UML和模式应用(架构师必备).part03.rar

    26.2 一些GRASP原则是对其他设计模式的归纳 26.3 设计中发现的“分析”:领域模型 26.4 工厂(Factory) 26.5 单实例类(GoF) 26.6 具有不同接口的外部服务问题的结论 26.7 策略(GoF) 26.8 组合(GoF)和...

    UML和模式应用(架构师必备).part04.rar

    26.2 一些GRASP原则是对其他设计模式的归纳 26.3 设计中发现的“分析”:领域模型 26.4 工厂(Factory) 26.5 单实例类(GoF) 26.6 具有不同接口的外部服务问题的结论 26.7 策略(GoF) 26.8 组合(GoF)和...

    UML和模式应用(架构师必备).part08.rar

    26.2 一些GRASP原则是对其他设计模式的归纳 26.3 设计中发现的“分析”:领域模型 26.4 工厂(Factory) 26.5 单实例类(GoF) 26.6 具有不同接口的外部服务问题的结论 26.7 策略(GoF) 26.8 组合(GoF)和...

    UML和模式应用(架构师必备).part05.rar

    26.2 一些GRASP原则是对其他设计模式的归纳 26.3 设计中发现的“分析”:领域模型 26.4 工厂(Factory) 26.5 单实例类(GoF) 26.6 具有不同接口的外部服务问题的结论 26.7 策略(GoF) 26.8 组合(GoF)和...

    GPT:Chat的计算合成与人机协同创新

    爱因斯坦1936年10月在纪念美国高等教育300年的会议上发表了一篇名为《on education》的演讲,认为“教育首要目标的永远应该是独立思考和判断的总体能力的培养,而不是获取特定的知识”,面对ChatGPT所引发的新挑战,...

    Git权威指南PDF完整版

    10.7 Hello World 引发的新问题/ 124 10.8 文件忽略/ 125 10.9 文件归档/ 129 第11章 历史穿梭/ 130 11.1 图形工具:gitk/ 130 11.2 图形工具:gitg/ 131 11.3 图形工具:qgit/ 135 11.4 命令行工具/ 140 11.4.1 ...

    大数据研究现状.pptx

    用户的"迁移":从电脑端转向移动端 传播模式的改变:由垂直传播变为裂变传播 信息筛选机制:从自行选择到协同过滤 数据新闻自身:长生产周期需要长"保质期" 2 以"分享"为核心的生产策略 内容有谈资、爆点要凸显、...

    操作系统(内存管理)

    不过,您可能没有用一些时间去思考它们在您的操作系统中是如何实现的。本节将向您展示 malloc 和 free 的一个最简化实现的代码,来帮助说明管理内存时都涉及到了哪些事情。 要试着运行这些示例,需要先 复制本代码...

    内存管理内存管理内存管理

    不过,您可能没有用一些时间去思考它们在您的操作系统中是如何实现的。本节将向您展示 malloc 和 free 的一个最简化实现的代码,来帮助说明管理内存时都涉及到了哪些事情。 要试着运行这些示例,需要先复制本...

    亮剑.NET深入体验与实战精要2

    此次将长期的思考、感悟,多年的系统开发、设计和团队管理经验,以及深入分析众多项目实战的宝贵成果和盘托出,力求将编程思想与具体实践融为一体,提炼出适合于广大读者快速理解和彻底掌握.NET软件开发的最佳学习...

    亮剑.NET深入体验与实战精要3

    此次将长期的思考、感悟,多年的系统开发、设计和团队管理经验,以及深入分析众多项目实战的宝贵成果和盘托出,力求将编程思想与具体实践融为一体,提炼出适合于广大读者快速理解和彻底掌握.NET软件开发的最佳学习...

Global site tag (gtag.js) - Google Analytics