引例
方案一
说明:
- 不满足OCP,添加新的排序算法或修改某个已有排序算法需要重新编译整个类
- 可复用性差,Sorting类不可被直接复用
方案二
将客户类和算法类分开
说明:Sorting类可复用,但Sorting类仍不满足OCP
方案三
分离变化点:排序算法内部逻辑可能变化,排序算法个数可能变化,于是做成层次类,实现一个抽象的Sort接口
说明:满足开闭原则、依赖倒置原则
Client类和算法实现类都依赖Sort抽象接口
具体使用而言,在 Client 中的 Sort 对象实例化某个具体的子类即可
还有一个问题:Client使用不同的Sort方法时可能需要进行重复的初始化、计算排序时间等与Sort层次类提供功能无关的工作
方案四
在Client和Sort层次类之间加上一个负责初始化/全局控制的类,用以协调Client和Sort层次类,即环境类Context
代码实现
// Sort抽象接口
public interface Sort {
int[] sort(int[] num);
}
// 具体排序类实现
public class BubbleSort implements Sort{
@Override
public int[] sort(int[] num) {
int n = num.length;
for (int i = 0; i < n; i++) {
for (int j = 0; j < n - i - 1; j++) {
if (num[j] > num[j + 1]) {
int temp = num[j];
num[j] = num[j + 1];
num[j + 1] = temp;
}
}
}
return num;
}
}
// Context环境类的实现
public class Context {
private Sort s;
private long startTime;
private long endTime;
public Context(Sort s) {
this.s = s;
}
public void startExc() {
startTime = System.currentTimeMillis();
}
public void endExc() {
endTime = System.currentTimeMillis();
}
public long getExcTime() {
long exeTime = 0;
exeTime = endTime - startTime;
return exeTime;
}
public int[] sortIntArray(int[] a) {
return s.sort(a);
}
}
// Client客户端代码实现
public class Client {
public static void main(String[] args) {
int[] arr = {64, 34, 25, 12, 22, 11, 90};
Sort s = new BubbleSort();
Context con = new Context(s);
con.startExc();
arr = con.sortIntArray(arr);
con.endExc();
System.out.println(Arrays.toString(arr));
System.out.println(con.getExcTime());
}
}
说明:这个设计模式仍有修改空间,应该通过在Sort具体类的sort方法中直接调用con.startExc()和con.endExc() 方法,这样得到的运行时间更加准确
方案五
在Sort层次类和Context环境类之间增加一条反向依赖
理论
定义
通过将一系列实现相同功能的算法封装起来,形成层次类,是得它们可以相互替换,且算法的变化不会影响使用算法的客户
说明
对象行为模式
通用结构
使用场景
- 一个系统需要动态地在几种算法中选择一种时,可将每个算法封装到策略类中
- 一个类中以条件语句并列起来的多种行为,每个条件分支可被封装到策略类中
课后练习
练习一
设计思路一:使用策略工厂的思路,DiscountStrategy作为抽象接口下接具体的discount策略做成一个打折策略层次类,DiscountStrategyFactory作为环境类,OrderService作为Client调用对应DiscountStrategyFactory再使用对应的打折策略
DiscountStrategyFactory实现代码:
public class DiscountStrategyFactory {
private static final Map<OrderType, DiscountStrategy> strategies = new HashMap<OrderType, DiscountStrategy>();
static {
strategies.put(OrderType.NORMAL, new NormalDiscountStrateg());
strategies.put(OrderType.GROUPON, new GrouponDiscountStrategy());
strategies.put(OrderType.PROMOTION, new PromotionDiscountStrategy());
}
public static DiscountStrategy getDiscountStrategy(OrderType type) {
return strategies.get(type);
}
}
练习二