设计原则和设计思想, 远比设计模式普适和重要, 掌握设计原则和思想, 甚至可以自己创建出设计模式
策略模式是将策略的 定义
, 创建
, 使用
三部分解耦
1. 策略的定义
// 策略. 算法的接口
public interface Strategy {
void algorithmInterface();
}
public class ConcreteStrategyA implements Strategy {
@Override
public void algorithmInterface() {
//具体的算法...
}
}
public class ConcreteStrategyB implements Strategy {
@Override
public void algorithmInterface() {
//具体的算法...
}
}
2. 策略的创建
因为要根据不同情况创建不同策略, 为了封装策略的创建过程, 可以将这个过程抽到工厂类中, 让工厂类实例化策略对象 (这里又可以用到工厂模式
). 而且,
- 如果策略对象是无状态的, 就是说如果策略对象的构造方法有会变动参数 ,可以作为类似 spring siglton 的模式存在, 可以在工厂类中先创建好策略对象, 缓存到工厂的 hashmap 等待使用;
- 如果策略对象是有状态的, 就是说策略对象的构造方法中没有会变动的参数, 可以作为类似 spring prototype 的模式存在, 则要在每次调用工厂类的 getStrategy() 方法中创建新的策略对象;
// 工厂类实例化无状态类策略
public class StrategyFactory {
private static final Map<String, Strategy> strategies = new HashMap<>();
static {
strategies.put("A", new ConcreteStrategyA());
strategies.put("B", new ConcreteStrategyB());
}
public static Strategy getStrategy(String type) {
if (type == null || type.isEmpty()) {
throw new IllegalArgumentException("type should not be empty.");
}
return strategies.get(type);
}
}
// 工厂类实例化有状态类策略
public class StrategyFactory {
public static Strategy getStrategy(String type) {
// 出现大量 if-else 判断代码. 而策略模式是可以消除这种大量判断代码的, 具体做法如下
if (type == null || type.isEmpty()) {
throw new IllegalArgumentException("type should not be empty.");
}
if (type.equals("A")) {
return new ConcreteStrategyA();
} else if (type.equals("B")) {
return new ConcreteStrategyB();
}
return null;
}
}
3. 策略的使用
项目中, 经常有多层嵌套的 if-else 判断, 又说策略模式可以消除这种判断, 怎么做到的呢? 可以让策略的使用方, 先将策略和策略的使用条件封装成一个对象
, 再放到一个 list 中缓存
这种办法, 调用策略时就能用 for 循环遍历筛选. 如下, 完整的实现了一个需求:
- 对文件排序. 但根据文件大小的不同, 会选择内存排序, 多线程的外排序, mapreduce 排序这3个不同算法.算法根据文件大小进行筛选
// 策略接口
interface ISortAlg {
void sort(String filePath);
}
// 策略实现类
class QuickSort implements ISortAlg {
@Override
public void sort(String filePath) {
//...
}
}
class ExternalSort implements ISortAlg {
@Override
public void sort(String filePath) {
//...
}
}
class ConcurrentExternalSort implements ISortAlg {
@Override
public void sort(String filePath) {
//...
}
}
class MapReduceSort implements ISortAlg {
@Override
public void sort(String filePath) {
//...
}
}
// 策略工厂
class SortAlgFactory {
private static final Map<String, ISortAlg> algs = new HashMap<>();
static {
algs.put("QuickSort", new QuickSort());
algs.put("ExternalSort", new ExternalSort());
algs.put("ConcurrentExternalSort", new ConcurrentExternalSort());
algs.put("MapReduceSort", new MapReduceSort());
}
public static ISortAlg getSortAlg(String type) {
if (type == null || type.isEmpty()) {
throw new IllegalArgumentException("type should not be empty.");
}
return algs.get(type);
}
}
// 策略调用方
class Sorter {
private static final long GB = 1000 * 1000 * 1000;
private static final List<AlgRange> algs = new ArrayList<>();
static {
algs.add(new AlgRange(0, 6*GB, SortAlgFactory.getSortAlg("QuickSort")));
algs.add(new AlgRange(6*GB, 10*GB, SortAlgFactory.getSortAlg("ExternalSort")));
algs.add(new AlgRange(10*GB, 100*GB, SortAlgFactory.getSortAlg("ConcurrentExternalSort")));
algs.add(new AlgRange(100*GB, Long.MAX_VALUE, SortAlgFactory.getSortAlg("MapReduceSort")));
}
public void sortFile(String filePath) {
File file = new File(filePath);
long fileSize = file.length();
ISortAlg sortAlg = null;
/** 原先的 if-else 判断, 改成 for 遍历每个策略, 判断策略调用条件是否成立 */
for (AlgRange algRange : algs) {
if (algRange.inRange(fileSize)) {
sortAlg = algRange.getAlg();
break;
}
}
sortAlg.sort(filePath);
}
/** Algorithm 范围, 封装策略和策略调用的条件 */
private static class AlgRange {
private long start;
private long end;
private ISortAlg alg;
public AlgRange(long start, long end, ISortAlg alg) {
this.start = start;
this.end = end;
this.alg = alg;
}
public ISortAlg getAlg() {
return alg;
}
// 判断文件大小是否在范围内
public boolean inRange(long size) {
return size >= start && size < end;
}
}
}
注解策略的进阶
现在唯一的问题是, 当新增策略时, 要修改策略工厂类. 这个问题可以通过策略加上注解
, 策略工厂扫描解析注解
来解决
(1) 定义注解 : 用自定义注解来标注有哪些策略类
(2) 创建注解 : 策略工厂搜索被自定义注解的策略类, 通过反射记载策略类, 创建策略对象