今天我们来讨论一下设计模式中最常用的一种行为模式----策略模式,在实际的项目中,我们经常会解决类似这样的业务场景,比如,对于同一件事情,在不同时间或不同状态下,执行不同的逻辑,我们就可以通过策略模式来封装具体的算法规则,实际使用模块只需要知道使用何种策略即可,今天我们就通过两个数的运算来模拟多规则下策略模式如何设计并改善。
策略模式(Strategy Pattern)中,定义出一套算法族,让他们可以根据不同场景进行替换,同时通过定义配置对象来对外提供相应的算法对象。目的是解决多场景下,核心处理逻辑类似,判断语句过多的问题。
给定两个数,num1,num2,分别计算加减乘除。
1、定义逻辑处理总接口
/**
* 数据计算接口
* 优点
* 定义数据计算的统一接口,
* 便于后续使用时不关心每个类中具体方法的定义,
* 实现类可以实现多个接口,因此此处不用抽象类。
* 缺点
* 1、该接口存在多个方法,而后续操作有些不适用,就需要实现很多无用方法,增加代码量。
* 2、当接口类中增加一个新的方法时,实现类必须全体一起增加该方法的实现。
*/
public interface CalculationInterface {
//用于处理两个数的运算
public int mathod(int num1, int num2);
}
2、实现加减乘除算法类
/**
* 数据处理实现:加法策略实现类
*/
public class Addition implements CalculationInterface {
/**
* @param num1 数据1
* @param num2 数据2
* @return 两数之和
*/
@Override
public int mathod(int num1, int num2) {
return num1 + num2;
}
}
/**
* 数据处理实现:减法策略实现类
*/
public class Subtraction implements CalculationInterface {
/**
* @param num1 数据1
* @param num2 数据2
* @return 两数相减
*/
@Override
public int mathod(int num1,int num2) {
return num1 - num2;
}
}
/**
* 数据处理实现:乘法策略实现类
*/
public class Multiplication implements CalculationInterface {
/**
* @param num1 数据1
* @param num2 数据2
* @return 两数相乘
*/
@Override
public int mathod(int num1, int num2) {
return num1 * num2;
}
}
/**
* 数据处理实现:除法策略实现类
*/
public class Division implements CalculationInterface {
/**
* @param num1 数据1
* @param num2 数据2 不可以为0
* @return 两数相除
*/
@Override
public int mathod(int num1, int num2) {
if (num2 == 0) throw new RuntimeException("除数不能为0");
return num1 / num2;
}
}
3、构建配置对象
/**
* 提供配置环境
* 统一策略的创建,
* 统一策略方法的使用,
* 对外不需要关心具体策略内部如何实现,
* 不需要关心如何创建相关策略类,执行相应策略的方式,
* 只需要知道有哪些策略,该使用哪一策略。
*/
public class Context {
private CalculationInterface anInterface;
//通过统一配置环境,创建不同策略实现类。
public Context(CalculationInterface anInterface) {
this.anInterface = anInterface;
}
//提供参数统一入口,根据创建不同的实现类,执行不同策略,
public int logic(int num1, int num2) {
return anInterface.mathod(num1, num2);
}
}
4、策略模式执行类
/**
* 策略模式测试
*/
public class StrategyTest {
public static void main(String[] args) {
int add = 0, sub = 0, mul = 0, div = 0;
if (StrategyType.getAdd().equals("加")) {
Context addition = new Context(new Addition());
add = addition.logic(400, 200);
}
if (StrategyType.getSub().equals("减")) {
Context subtraction = new Context(new Subtraction());
sub = subtraction.logic(400, 200);
}
if (StrategyType.getMul().equals("乘")) {
Context multiplication = new Context(new Multiplication());
mul = multiplication.logic(400, 200);
}
if (StrategyType.getDiv().equals("除")) {
Context division = new Context(new Division());
div = division.logic(400, 200);
}
System.out.println("加:" + add + " 减:" + sub + " 乘:" + mul + " 除:" + div);
}
}
5、定义策略类型
/**
* 定义策略类型
*/
public class StrategyType {
private static final String add = "加";
private static final String sub = "减";
private static final String mul = "乘";
private static final String div = "除";
public static String getAdd() {
return add;
}
public static String getSub() {
return sub;
}
public static String getMul() {
return mul;
}
public static String getDiv() {
return div;
}
}
以上就是策略模式的具体使用方式,但是我们不难发现,还是需要客户端去判断不同类型下,如何创建,不仅比较繁琐,同时还需要知道具体策略才行,这对客户端来说要求太高了。
我们将客户端判断部分封装到配置类中,这样客户端不需要关心何种类型下如何实现对应算法,只需要实现配置类即可,简化操作。
1、改进配置类
/**
* 配置类改善
* 原因
* 使用策略模式后,客户端依然需要判断在具体条件下,创建具体的策略,因此改造配置类
* 将判断创建具体策略的行为从客户端隔离,让客户端彻底不再判断
* 方案
* 创建具体策略时传入相关类型,交给配置类进行判断
*/
public class ContextImprove {
private CalculationInterface anInterface;
//通过统一配置环境,创建不同策略实现类。
public ContextImprove(String strategyType) {
if (strategyType.equals("加")) {
this.anInterface = new Addition();
}
if (strategyType.equals("减")) {
this.anInterface = new Subtraction();
}
if (strategyType.equals("乘")) {
this.anInterface = new Multiplication();
}
if (strategyType.equals("除")) {
this.anInterface = new Division();
}
}
//提供参数统一入口,根据创建不同的实现类,执行不同策略,
public int logic(int num1, int num2) {
return anInterface.mathod(num1, num2);
}
}
2、测试
/**
* 策略模式测试
*/
public class StrategyTest {
public static void main(String[] args) {
ContextImprove contextImprove = new ContextImprove(StrategyType.getAdd());
System.out.println(StrategyType.getAdd() + ":" + contextImprove.logic(100, 200));
}
}
此时我们可以看到,客户端使用时根本不需要关心如何创建相应的算法类,只需要创建配置类即可,但是不难发现上面依然存在很多判断在配置类中,这里可以用抽象工厂来替换掉,本文不做叙述,大家可以自行研究。