策略模式介绍
策略模式属于Java23种设计模式中的行为型模式。在实际项目开发使用较多。也是面试经常会问到的知识点。
策略模式(strategy pattern)的原始定义是:定义一系列算法,将每一个算法封装起来,并使它们可以相互替换。策略模式让算法可以独立于使用它的客户端而变化。
策略模式的主要角色如下:
抽象策略(Strategy)类:这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需的接口。
具体策略(Concrete Strategy)类:实现了抽象策略定义的接口,提供具体的算法实现或行为。
环境或上下文(Context)类:是使用算法的角色, 持有一个策略类的引用,最终给客户端调用。
该方法委托策略变量调用具体策略所实现的策略接口中的方法(实现接口的类重写策略中的方法,来完成具体功能)
策略模式实现
先看一个简单的实现,快速了解什么是策略模式。
1、定义一个策略接口
public interface Strategy {
/**
* 执行任务
*/
void executeTask();
}
2、具体的策略实现,这里实现两个。StrategyA和StrategyB
public class StrategyA implements Strategy {
@Override
public void executeTask() {
System.out.println("执行任务A");
}
}
public class StrategyB implements Strategy {
@Override
public void executeTask() {
System.out.println("执行任务B");
}
}
3、策略上下文
public class Context {
private Strategy strategy;
public Context(Strategy strategy) {
this.strategy = strategy;
}
public void executeTask(){
strategy.executeTask();
}
}
4、策略调用
@Test
public void test001(){
Context context = new Context(new StrategyA());
context.executeTask();
}
相信到这里对策略模式都有了一定的了解,接下来具体看下如果使用策略模式消除if else
策略模式消除if else
1、定义一个实体类
@Datapublic class StrategyModelTest {
private String name;
private String type;
}
2、模拟数据,用于之后策略使用。
public class StrategyList {
/**
* 用来模拟数据,比如是数据库中查询出来的数据 *@return java.util.List<StrategyModelTest>
*/
public static List<StrategyModelTest> getList() {
List<StrategyModelTest> strategyModelTestList = new ArrayList<>();
StrategyModelTest strategyModelTestA = new StrategyModelTest();
strategyModelTestA.setName("name");
strategyModelTestA.setType("001");
strategyModelTestList.add(strategyModelTestA);
StrategyModelTest strategyModelTestB = new StrategyModelTest();
strategyModelTestB.setName("name");
strategyModelTestB.setType("002");
strategyModelTestList.add(strategyModelTestB);
StrategyModelTest strategyModelTestC = new StrategyModelTest();
strategyModelTestC.setName("name");
strategyModelTestC.setType("003");
strategyModelTestList.add(strategyModelTestC);
return strategyModelTestList;
}
}
3、策略接口类
public interface StrategyTest {
/**
* 执行任务 * @author: mkj * @param strategyModelTest
*/
void executeTask(StrategyModelTest strategyModelTest);
}
4、策略实现类,这次实现3个。
public class StrategyTestA implements StrategyTest {
@Override
public void executeTask(StrategyModelTest strategyModelTest) {
System.out.println("执行任务B"+strategyModelTest.getName());
}
}
public class StrategyTestB implements StrategyTest {
@Override
public void executeTask(StrategyModelTest strategyModelTest) {
System.out.println("执行任务A"+strategyModelTest.getName());
}
}
public class StrategyTestC implements StrategyTest {
@Override
public void executeTask(StrategyModelTest strategyModelTest) {
System.out.println("执行任务C"+strategyModelTest.getName());
}
}
5、策略上下文
public class ContextTest {
private StrategyTest strategyTest;
public ContextTest(StrategyTest strategyTest) {
this.strategyTest = strategyTest;
}
public void executeTask(StrategyModelTest strategyModelTes) {
strategyTest.executeTask(strategyModelTes);
}
}
6、先看一个反例,使用if else 实现。
可以看见代码里有好几个if else ,这还只是示例,如果在实际开发中,这种逻辑只会更多。
/**
* 不使用策略 * @author: mkj
*/
@Test
public void test(){
//这是只是模拟数据,type也可以是当参数传递。
List<StrategyModelTest> list=StrategyList.getList();
for(StrategyModelTest strategyModelTest:list){
if("001".equals(strategyModelTest.getType())){
System.out.println("执行001的业务逻辑");
}else if("002".equals(strategyModelTest.getType())){
System.out.println("执行002的业务逻辑");
}else{
System.out.println("执行003的业务逻辑");
}
}
7、下面看正例。
想要消除if else ,还需要实现一个类,用Map封装策略类。如下:
public class StrategyTestFactory {
public StrategyTestFactory() {
}
/**
* 使用map来存放策略类,用来消除if else
*/
private static Map<String, StrategyTest> strategyMap;
public static void init() {
strategyMap = new HashMap<>(8);
strategyMap.put("001", new StrategyTestA());
strategyMap.put("002", new StrategyTestB());
strategyMap.put("003", new StrategyTestC());
}
public static StrategyTest getStrategy(String type) {
return strategyMap.get(type);
}
}
8、策略实现:
/**
* 使用策略
* @author: mkj
*/
@Test
public void strategyTest(){
List<StrategyModelTest> list = StrategyList.getList();
StrategyTestFactory.init();
for (StrategyModelTest strategyModelTest : list){
StrategyTestFactory.getStrategy(strategyModelTest.getType()).executeTask(strategyModelTest);
}
}
从示例中可以看出,代码中一个if else 都没有,而且代码更加简洁,也更加利于扩展,如果再有一个不同逻辑,实现一个策略类就可以了,其他代码基本不用动。
策略模式应用场景
1、有多个相似的类,只有行为有差异的情况下,可以考虑使用策略模式。
2、需要在运行时动态切换算法的情况下,可以使用策略模式。
3、一个系统需要在不同时间应用不同的业务规则情况下,可以使用策略模式。
4、在一个系统中,有许多类需要根据某种规则进行排序,查找等操作的情况下,可以使用策略模式。