概述
定义一组算法,将每个算法都封装起来,并且使它们之间可以互换。策略模式的决定权在用户,系统本身提供不同算法的实现,新增或者删除算法,对各种算法做封装。因此,策略模式多用在算法决策系统中,外部用户只需要决定用哪个算法即可
涉及角色
- Context
封装角色:它也叫做上下文角色,起承上启下封装作用,屏蔽高层模块对策略、算法的直接访问,封装可能存在的变化。 - Strategy
抽象策略角色:策略、算法家族的抽象,通常为接口,定义每个策略或算法必须具有的方法和属性。各位看官可能要问了,类图中的AlgorithmInterface是什么意思,嘿嘿,algorithm是“运算法则”的意思,结合起来意思就明白了吧。 - ConcreteStrategy
具体策略角色(多个):实现抽象策略中的操作,该类含有具体的算法
UML
使用场景
- 如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为
- 一个系统需要动态地在几种算法中选择一种
- 如果一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句来实现
优点
- 策略模式提供了管理相关的算法族的办法。策略类的等级结构定义了一个算法或行为族。恰当使用继承可以把公共的代码移到父类里面,从而避免代码重复。
- 避免使用多重条件判断,使用策略模式可以避免使用多重条件(if-else)语句。多重条件语句不易维护,它把采取哪一种算法或采取哪一种行为的逻辑与算法或行为的逻辑混合在一起,统统列在一个多重条件语句里面,比使用继承的办法还要原始和落后。
- 扩展性良好
缺点
- 客户端必须知道所有的策略类,并自行决定使用哪一个策略类。这就意味着客户端必须理解这些算法的区别,以便适时选择恰当的算法类。换言之,策略模式只适用于客户端知道算法或行为的情况。
- 由于策略模式把每个具体的策略实现都单独封装成为类,如果备选的策略很多的话,那么对象的数目就会很可观。
代码示例
抽象策略类
package com.designpattern.strategy;
public interface Strategy {
public String strategyMethod();
}
具体策略类
package com.designpattern.strategy;
public class ConcreteStrategyA implements Strategy {
@Override
public String strategyMethod() {
// TODO Auto-generated method stub
return "ConcreteStrategyA";
}
}
package com.designpattern.strategy;
public class ConcreteStrategyB implements Strategy {
@Override
public String strategyMethod() {
// TODO Auto-generated method stub
return "ConcreteStrategyB";
}
}
环境角色类
package com.designpattern.strategy;
public class Context {
// 持有一个具体策略的对象
private Strategy strategy;
public Context(Strategy strategy){
this.strategy = strategy;
}
public String contextMethod(){
return strategy.strategyMethod();
}
}
测试主类
package com.designpattern.strategy;
public class TestMain {
public static void main(String[] args) {
// 选择并创建需要使用的策略对象
Strategy strategy = new ConcreteStrategyA();
// 创建环境
Context context = new Context(strategy);
// 执行业务逻辑
String result = context.contextMethod();
System.out.println("业务逻辑返回结果为:" + result);
strategy = new ConcreteStrategyB();
context = new Context(strategy);
result = context.contextMethod();
System.out.println("业务逻辑返回结果为:" + result);
}
}