# 本人学习时的笔记,有错必改,不喜勿喷 #
2.1 动机
在软件构建过程中,某些对象使用的算法可能多种多样,经常改变,如果将这些算法都编码到对象中,将会使对象变得异常复杂;而且有时候支持不使用的算法也是一个性能负担。
2.2 模式定义
定义一系列算法,把它们一个个封装起来,并且使它们可互相替换(变化)。该模式使得算法可独立于使用它的客户程序(稳定)而变化(扩展,子类化)
2.3 案例
用户登录,通过不同的角色id进入不同的用户界面,已存在的角色有:系统管理员、教务处管理员、教师以及学生,要求再增加一个“班主任”角色,使得班主任也能进入此系统。
应用策略模式构建的类图如下:
2.4 策略模式在主流框架中的应用
- 策略模式在JDK中的应用
通过阅读JDK关于sort方法的源码我们可以得知,如果我们调用的是带有Comparator接口参数的方法,此接口定义了一个用于排序规则的抽象方法compare,通过观察其实我们不难发现,Comparator接口就是策略模式中的策略接口,其定义了一个排序算法,而具体的策略实现则需要由用户自定义实现。
源码如下:
对此,做一个简单的实验验证其真实性:
- 使用不带Comparator接口的方法,使用的是默认的不带其他条件的排序算法;
- 使用带Comparator接口的方法,本实验中用属性为age和height的Person对象进行演示,排序方法为按年龄从小到大排序,如果年龄相同则按照身高从大到小排序。
代码:
总结:通过本案例可以得知,array中的sort方法使用策略模式,使得用户可以动态自定义排序规则,从而得到符合预期的排序结果。
- 策略模式在springMVC中的应用
通过查阅资料,发现在springMVC中,提供SpringWebMVC的集中访问点——DispatcherServlet在进行转发前需要对九大件进行初始化操作,而除了上传文件没有获取默认策略,其他的八大件都应用了策略模式,流程调用如下:
其中,调用了getDefalutStrategy方法的代码如下:
其中,getDafalutStrategy的实现实际上是使用了Properties中的哈希值,代码如下:
最后,通过spring的Resource配置文件将其所对应的配置映射到Map容器中,完成了对组件的初始化,代码如下:
总结:通过此案例我们可以得知,在DispatcherServlet对九大件的初始化中,因为有策略模式的存在,使得系统能够更加灵活,可以由spring的classPathResource将配置文件DispatcherServlet.properties中的配置加载到一个Map容器中,从而根据相对应的类型调用相应的实现完成初始化工作。
2.5 策略模式的扩展分析
① 使用模板方法(Temlpate Method)扩展策略模式
模板方法即是定义一个操作中的算法的骨架,而将一些步骤延迟到子类中,使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤,其用最简洁的机制(虚函数的多态性)为很多应用程序框架提供了灵活的扩展点,是代码复用方面的基本实现结构。
在本次登录案例中,模块方法的使用已经有所体现:运行mfl.roleLogin()方法,在系统动态获取到相应的roleId后再进入对应的角色功能界面。体现了一种晚绑定的机制。
② 使用装饰器模式(Decorator)修正策略模式可能带来的弊端
在本案例中,新添加的班主任类,很可能只是比普通教师类多了一个“管理班级”的方法,因此如果不对实际情况就直接使用策略模式,将使得策略类冗余并且加重系统负担,修改后的类图如下:
③ 使用享元模式以解决大量策略类给系统带来的负担,其奥义在于运用共享技术有效地支持大量细粒度的对象,即当策略类的粒度很小时,可以建立一个对象共享池,需要时再向其中申请即可,避免了创建大量的策略类。