策略模式
定义: Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it
定义一族算法类,将每个算法分别封装起来,让它们可以互相替换。策略模式可以使算法的变化独立于使用它们的客户端(这里的客户端代指使用算法的代码)。
策略模式被广泛使用
(1)如redis淘汰策略,ttl 从已设置过期时间的数据集中挑选将要过期的数据淘汰,lru从已设置过期时间的数据集中挑选最近最少使用的数据淘汰,可以通过策略模式动态设置淘汰算法。
(2)如文件排序,根据文件大小,使用文件排序,内部并发文件排序,或者mapreduce排序。
既可以使得代码低耦合高内聚,又可以减少代码的if…else冗杂分支。
完整的策略模式应该包括策略的定义、策略的创建和策略的使用
代码演示1 缓存淘汰,使用不同算法指定缓存淘汰策略
策略定义
public interface EvictionStrategy {
void evict();
}
策略创建
public class ConcreteEvictionStrategyA implements EvictionStrategy {
@Override
public void evict() {
}
}
public class ConcreteEvictionStrategyB implements EvictionStrategy {
@Override
public void evict() {
}
}
public class EvictionStrategyFactory {
private static final Map<String, EvictionStrategy> strategies = new HashMap<>();
static {
strategies.put("A", new ConcreteEvictionStrategyA());
strategies.put("B", new ConcreteEvictionStrategyB());
}
public static EvictionStrategy getStrategy(String type) {
if (type == null || type.isEmpty()) {
throw new IllegalArgumentException("type should not be empty");
}
return strategies.get(type);
}
}
策略使用
public class UserCache {
private Map<String, User> cacheData = new HashMap<>();
private EvictionStrategy evictionStrategy;
public UserCache(EvictionStrategy evictionStrategy) {
this.evictionStrategy = evictionStrategy;
}
}
public class Application {
public static void main(String[] args) throws IOException {
EvictionStrategy evictionStrategy = null;
Properties properties = new Properties();
properties.load(new FileInputStream("./config.properties"));
String type = properties.getProperty("eviction_type");
evictionStrategy = EvictionStrategyFactory.getStrategy(type);
//运行时动态确定,根据配置文件的配置决定使用哪种策略
UserCache userCache = new UserCache(evictionStrategy);
}
}
代码演示2 文件内容排序,按照文件大小,选择不同策略排序
策略定义
public interface ISortAlg {
void sort(String filePath);
}
策略创建
public class QuickSort implements ISortAlg {
@Override
public void sort(String filePath) {
}
}
public class ExternalSort implements ISortAlg {
@Override
public void sort(String filePath) {
}
}
public class ConcurrentExternalSort implements ISortAlg {
@Override
public void sort(String filePath) {
}
}
public class MapReduceSort implements ISortAlg {
@Override
public void sort(String filePath) {
}
}
public class SortAlgFactory {
private static final Map<String, ISortAlg> sortAlgs = new HashMap<>();
static {
sortAlgs.put("QuickSort", (ISortAlg) new QuickSort());
sortAlgs.put("ExternalSort", (ISortAlg) new ExternalSort());
sortAlgs.put("ConcurrentExternalSort", (ISortAlg) new ConcurrentExternalSort());
sortAlgs.put("MapReduceSort", (ISortAlg) new MapReduceSort());
}
public static ISortAlg getSortAlg(String type) {
if (type == null || type.isEmpty()) {
throw new IllegalArgumentException("type should not be empty");
}
return sortAlgs.get(type);
}
}
策略使用
public 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;
for (AlgRange algRange : algs) {
if (algRange.inRange(fileSize)) {
sortAlg = algRange.getAlg();
break;
}
}
sortAlg.sort(filePath);
}
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;
}
}
}
代码参考: https://github.com/hero-joey/java-study-examples/tree/master/designpatten/src/com/hero/designpatten