策略模式
概述
《设计模式》一书中对于 “策略模式” 的意图描述如下:
定义一系列算法,将它们一个个封装起来,并是他们可以相互替代
一般策略模式的 UML 图如下所示:
一般在以下几种情况中使用策略模式:
- 许多相关的类仅仅是行为有异。“策略” 提供了一种用多个行为中的一个行为来配置一个类的方法
- 需要使用一个算法的不同变体。比如,在不同的使用场景下,可能需要考虑时间/空间复杂度较为优秀的算法
- 算法使用了客户端不应该知道的数据
- 一个类定义了多种行为,并且这些行为在这个类的操作中一多个条件语句的形式出现
具体示例
假设现在存在一个需要计算利息的的测算模型,对于不同的测算模型,需要采取不同的利息测算算法,一般常见的测算算法分为等额本金和等额本息,可能不同的资产管理公司还会存在其它的测算算法,为了能够可扩展地对利息进行测算,我们需要将利息的测算和当前的上下文进行分离,有具体的使用场景来决定采用何种测算算法
首先,我们定义我们的利息测算的接口策略 InterestCalStrategy
:
public interface InterestCalStrategy {
/**
根据传入的本金信息计算对应的还本付息计划
*/
List<CashFlow> calInterest(List<Principal> prinicipalList);
}
对于不同的测算算法,我们需要定义不同的具体测算实例类:
public class EqualPrinicipalStrategy implements InterestCalStrategy {
@Override
public List<CashFlow> calInterest(List<Principal> prinicipalList) {
// 具体的测算逻辑
}
}
public class EqualInterestStrategy implements InterestCalStrategy {
@Override
public List<CashFlow> calInterest(List<Principal> prinicipalList) {
// 具体的测算逻辑
}
}
对于所处的上下文来讲,它只需要持有对应测算算法的引用即可:
public class ApplicationContext {
private InterestCalStrategy strategy;
public void setStrategy(InterestCalStrategy strategy) {
this.strategy = strategy;
}
public List<CashFlow> calInterest(List<Principal> prinicipalList) {
return strategy.calInterest(prinicipalList);
}
}
实际使用时只需要由客户端选取对应的策略进行测算即可:
public class Application {
public static void main(String[] args) {
ApplicationContext context = new ApplicationContext();
// 等额本金的算法计算
context.setStrategy(new EqualPrinicipalStrategy());
context.calInterest(obtainPrinicipals());
// 等额本息的计算
context.setStrategy(new EqualInterestStrategy());
context.calInterest(obtainPrinicipals());
}
}
总结
策略模式的使用可以减少一些冗余的 if{}else{}
的使用,看起来和 "命令模式" 很相似。实际上这两个模式的最大区别在于 “命令模式” 强调需要做什么,而 “策略模式” 则在强调需要怎么做
参考:
[1] 《设计模式—可复用面向对象基础》
[2] https://stackoverflow.com/questions/4834979/difference-between-strategy-pattern-and-command-pattern