策略模式介绍

策略模式属于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、在一个系统中,有许多类需要根据某种规则进行排序,查找等操作的情况下,可以使用策略模式。

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐