策略模式引发的一些思考
一、前言
在这里直言不讳,这篇博文是看了某位老师新出的一段Java SE视频中的一道作业题,题目很简单,要求用策略模式实现排序;其中有三个字段,需要对这个三个字段(ID,NAME,AGE)进行排序,并且还要求有升序和降序的方式。对此有兴趣的朋友可以在网上搜索获取,在此不做任何说明,避免7+7的厄运。
也许是因为无聊吧,我做了这道简单不能再简单的题目。但是却给了我全新的思考感受,使我能够更有明确目的地在使用设计模式。
上面加粗的一句话貌似不好理解,太抽象,但又没有比这更能涵盖我所表达的意思了。换句话来说就是又增加了一条使用设计模式的心里暗示,即更有针对性地使用设计模式来解决应用场景中出现的问题。
我用一个更容易理解的比喻来解释一下:应用场景好比是一道菜,设计模式就好比是做这道菜所用的调料,用设计模式解决应用场景的问题也就好比是不同调料搭配起来会让这道菜具有不同的口味。由此引发的一个官方言论,即不要过分依赖设计模式,就好比是盐放的太多了,心里就该咒骂“打死卖盐的”了。
二、寻找应用场景中隐藏的问题
首先让我们来分析一下这道题目,题目要求很明确,就是排序。单拿这道题目作为应用场景,该应用场景中需要对三个字段进行排序;注意应用场景中的问题出现了
1.不仅仅实现排序功能,并且还要实现升序和降序的排序方式,详细点地说就意味着要实现3*2个排序算法。
2.应用场景中的三个字段在未来或许还会增加,并伴随着需要进行排序的可能性,也就是那个“3”会变化。
3.应用场景中的排序方式也是会变化的,即使这个假设放在这个应用场景中不太合适,但是也能说明一些问题的,问题本质上没太大的区别。
4.前三条是针对实现来说地,下面的几条针对可维护性层面来说。我之所以写出这篇博文,是因为我终于思考出设计模式对今后代码的维护也是有很大好处的。为什么说是“终于”?以往看过很多设计模式相关的书籍,里面也曾提到可维护性之类的话题;但是看了之后,也是能够理解,在解决实际问题的时候这些话题可就不翼而飞了,脑海里面只想着我要使用设计模式,而不是我该怎样使用设计模式。我在一番思考之后,对此类话题就很敏感了,换句话来说,选择使用哪种设计模式之前,又多了一条思考路径(前言也提到了这个话题)。
5.结合上述4条,用第五条明确指出代码维护带来的问题。就本文的应用场景,它要实现3*2个排序算法,也就是说以后要维护6个算法;如果两个乘数都在不断的增长,那就要维护N*N个算法。为此需要用更优雅的方式来设计,解决今后对代码维护引发的超大工作量问题。
三、三种设计方案
针对这个应用场景,我脑海里浮现出了三种设计方案。前两种方案是在没太理解策略模式之前经常用到的。后一种设计方案,看上去跟第二个很类似,但是却比前者更具内涵。下面是三种方案的方案以伪代码的方式介绍,就不放代码介绍了,一太占篇幅(好吧,我那是懒!),二此文最后提供第三种解决方案的源码。本文只阐述我思考后的成果,请勿沉浸在问题和代码表面上!
1.不使用模式
//(1)定义1个排序方式接口(策略接口)。针对本文所引用的应用场景,该接口提供两个方法,分别对Integer和String类型字段做比较操作;该方法返回的是int类型。 //(2)定义2个实现自先前定义的排序方式接口的实现类(具体策略),分别针对于正序和降序实现各自的算法。因该算法内部使用JDK提供的比较方法,其内部采用的是减法操作,故接口中的两个方法需返回int类型。//(3)定义3个实现自Comparator接口的排序算法实现类(环境),分别针对三个字段的排序。每个类都分别保有先前定义的排序方式接口的引用,并且实现的方法中需调用该接口引用所提供的相应方法。特别要注意本节用阿拉伯数字表明的地方。这个设计与第二个设计同样也定义了6个算法类,表面上看是差不多的;不过这里使用了两次策略模式,使维护的算法(类)变为N+N。