【设计模式】策略模式

引例


方案一

说明:

  1. 不满足OCP,添加新的排序算法或修改某个已有排序算法需要重新编译整个类
  2. 可复用性差,Sorting类不可被直接复用

方案二

将客户类和算法类分开

说明:Sorting类可复用,但Sorting类仍不满足OCP
方案三

分离变化点:排序算法内部逻辑可能变化,排序算法个数可能变化,于是做成层次类,实现一个抽象的Sort接口

说明:满足开闭原则、依赖倒置原则

Client类和算法实现类都依赖Sort抽象接口

具体使用而言,在 Client 中的 Sort 对象实例化某个具体的子类即可

还有一个问题:Client使用不同的Sort方法时可能需要进行重复的初始化、计算排序时间等与Sort层次类提供功能无关的工作
方案四

在Client和Sort层次类之间加上一个负责初始化/全局控制的类,用以协调Client和Sort层次类,即环境类Context

代码实现

java 复制代码
// Sort抽象接口
public interface Sort {
	int[] sort(int[] num);
}
java 复制代码
// 具体排序类实现
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;
	}
}
java 复制代码
// 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);
	}
}
java 复制代码
// 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环境类之间增加一条反向依赖

理论

定义

通过将一系列实现相同功能的算法封装起来,形成层次类,是得它们可以相互替换,且算法的变化不会影响使用算法的客户
说明

对象行为模式

通用结构

使用场景

  1. 一个系统需要动态地在几种算法中选择一种时,可将每个算法封装到策略类中
  2. 一个类中以条件语句并列起来的多种行为,每个条件分支可被封装到策略类中

课后练习

练习一

设计思路一:使用策略工厂的思路,DiscountStrategy作为抽象接口下接具体的discount策略做成一个打折策略层次类,DiscountStrategyFactory作为环境类,OrderService作为Client调用对应DiscountStrategyFactory再使用对应的打折策略

DiscountStrategyFactory实现代码:

java 复制代码
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);
	}
}

练习二


相关推荐
西京刀客7 小时前
macos安装openjdk17
java·macos·java17
Java中文社群8 小时前
面试官:如何实现动态线程池的任务编排?
java·后端·面试
mysla8 小时前
嵌入式学习day44-硬件—ARM体系架构
学习
lozhyf8 小时前
能发弹幕的简单视频网站
java·spring boot·后端
微露清风8 小时前
系统性学习数据结构-第三讲-栈和队列
java·数据结构·学习
AAA修煤气灶刘哥9 小时前
ES 地理查询玩明白,产品要的 “附近的店” 再也难不倒我!(附 DSL+Java 实战)
java·后端·elasticsearch
十八旬9 小时前
苍穹外卖项目实战(day-5完整版)-记录实战教程及问题的解决方法
java·开发语言·spring boot·redis·mysql
m0_749299959 小时前
Nginx主配置文件
java·服务器·nginx
╭╰4029 小时前
苍穹外卖优化-续
java·spring·mybatis
金銀銅鐵9 小时前
[Java] 枚举常量的精确类型一定是当前枚举类型吗?
java·后端