看清楚了策略模式的定义,角色组成以及通用的代码结构之后,我们就来看下策略模式在通用框架里的应用,来加深对策略模式的认识。
JDK 与策略模式在常用的Java 集合框架中,比较器 java.util.Comparator 的设计就采用了策略模式。Comparator 就是一个抽象的策略接口,只要一个类实现这个接口,自定 compare 方法,该类成为具体策略类,你可以在很多地址找到这个抽象策略接口的实现,官方在工具类 java.util.Comparators 里也提供 NaturalOrderComparator,NullComparator 两种具体策略类。而使用 Comparator 到的 java.util.Collections 类就是 Context 角色,将集合的比较功能封装成静态方法对外提供。
Spring Framework 与策略模式Spring 框架最早以 IoC 和 DI 两大特性著称,不需要开发者自己创建对象,而是通过 Spring IoC 容器识别然后实例化所需对象。在 Spring 中将执行创建对象实例的这个操作封装为一种算法,用接口类 org.springframework.beans.factory.support.InstantiationStrategy 进行声明,而具体策略类则有 org.springframework.beans.factory.support.SimpleInstantiationStrategy 和 org.springframework.beans.factory.support.CglibSubclassingInstantiationStrategy 两个,并且 CglibSubclassingInstantiationStrategy 是对 SimpleInstantiationStrategy 的继承扩展,也是 Spring 容器中真正使用到的策略类,具体应用的源码可参考 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory 类:
/** * Instantiate the given bean using its default constructor. * @param beanName the name of the bean * @param mbd the bean definition for the bean * @return a BeanWrapper for the new instance */ protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) { //... beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent); //... } 如何使用策略模式 实例应用俗话说学以致用,接触了策略模式后我们应该想想怎么用在自己日常开发项目中呢,这里就简单通过一个实例来说明下策略模式的使用方式。假设现在有个需求:需要对一个目录或者文件实现两种不同格式的解压缩方式:zip压缩和gzip压缩,也后续可能新增其他的解压缩方式。
我们首先将解压缩的算法抽象成抽象策略接口 CompressStrategy, 提供压缩方法 compress 和解压缩方法 uncompress,分别接受源文件路径和目的文件路径。
策略类在命名通常上以 Strategy 为后缀,来指明自身采用策略模式进行设计,以此简化与其他人沟通成本。
public interface CompressStrategy { public boolean compress(String source, String to); public boolean uncompress(String source, String to); }再对抽象策略接口进行实现,分别提供zip 压缩算法和 gzip 压缩算法,代码如下:
public class ZipStrategy implements CompressStrategy { @Override public boolean compress(String source, String to) { System.out.println(source + " --> " + to + " ZIP压缩成功!"); return true; } @Override public boolean uncompress(String source, String to) { System.out.println(source + " --> " + to + " ZIP解压缩成功!"); return true; } } public class GzipStrategy implements CompressStrategy { @Override public boolean compress(String source, String to) { System.out.println(source + " --> " + to + " GZIP压缩成功!"); return true; } @Override public boolean uncompress(String source, String to) { System.out.println(source + " --> " + to + " GZIP解压缩成功!"); return true; } }代码示例里的实现为了简化只是简单打印操作,具体实现可以参考 JDK API 进行操作。
接下来看下 Context 角色的代码实现:
public class CompressContext { private CompressStrategy compressStrategy; public CompressContext(CompressStrategy compressStrategy) { this.compressStrategy = compressStrategy; } public boolean compress(String source, String to) { return compressStrategy.compress(source, to); } public boolean uncompress(String source, String to) { return compressStrategy.uncompress(source, to); } }十分简单,只是传入一个具体算法,然后执行,到这里标准的策略模式就编写完毕了。客户端类只是根据需要指定的具体压缩策略对象传给 CompressContext 对象即可。如果要新增一个压缩算法,也只需对 CompressStrategy 接口提供新的实现即可传给 CompressContext 对象使用。
public class Client { public static void main(String[] args) { CompressContext context; System.out.println("========执行算法========"); context = new CompressContext(new ZipStrategy()); context.compress("c:\\file", "d:\\file.zip"); context.uncompress("c:\\file.zip", "d:\\file"); System.out.println("========切换算法========"); context = new CompressContext(new GzipStrategy()); context.compress("c:\\file", "d:\\file.gzip"); context.uncompress("c:\\file.gzip", "d:\\file"); } }