1. 什么是策略模式
- 定义一个算法簇, 将每个算法封装起来, 让他们可以相互替换; 并让算法的变化独立于调用算法的一方.
- 策略模式: 将算法的定义, 创建, 使用三方解耦
2. 解耦三方
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. 策略的创建
所谓策略的创建, 就是根据不同情况, 选择不同算法(策略)进行调用. 可以使用工厂类创建算法(策略)对象. 这里需要注意的是, 策略分为有状态和无状态的
- 无状态类策略:
不包含成员变量, 只有纯粹的算法实现. 这种情况不需要每次调用新建算法对象, 可以预先创建好缓存在工厂类中
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);
}
}
- 有状态类策略:
- 什么是有状态的策略
包含成员变量, 每次调用策略对象需要新建, 因此不能把策略对象需要在工厂模式的 get 方法中新建. (这里用 ConcreteStrategyA 和 ConcreteStrategyB 模拟)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. 用 for 消除大量的 if-else 判断使用哪种策略的逻辑
我们看到, 当策略对象不能简单的通过查表法从工厂类中获取时, 工厂类的 getStrategy() 就会出现大量的判断逻辑. 这种实现方式相当于把原来的 if-else 分支逻辑,从调用方转移到策略的创建方.
比如, 有一个需求: 对文件排序. 但根据文件大小的不同, 会选择内存排序, 多线程的外排序, mapreduce 排序这3个不同算法. 策略的选取已经不是简单的类型判断了, 怎么避免 if-else 的出现呢 ?
- 如下给出了解决办法: 将策略和满足策略调用的条件封装到一起, 用 for 循环判断哪个策略的调用成立, 然后获取策略对象
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;
}
}
}
网友评论