设计模式之策略模式(行为型)
Posted 一起来搬砖呀
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式之策略模式(行为型)相关的知识,希望对你有一定的参考价值。
1、策略模式定义
策略模式的定义:策略模式是一种行为型模式,定义了算法家族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化,不会影响到使用算法的客户。
比如商场收银时如何促销,用打折还是返利,其实都是一些算法,这些算法本身就是一种策略,这些算法是随时都可以互相替换的,这就是变化点,而封装变化是我们面向对象的一种很重要的思维方式
2、策略模式结构
Strategy 类,定义所有支持的算法的公共接口
/**
* 抽象策略类
*/
public abstract class Strategy
public abstract void algorithmInterface();
ConcreteStrategy,封装了具体的算法或行为,继承于 Strategy
/**
* 具体算法 A
*/
public class ConcreteStrategyA extends Strategy
/**
* 算法 A 实现
*/
@Override
public void algorithmInterface()
System.out.println("算法 A 实现");
/**
* 具体算法 B
*/
public class ConcreteStrategyB extends Strategy
/**
* 算法 B 实现
*/
@Override
public void algorithmInterface()
System.out.println("算法 B 实现");
/**
* 具体算法 C
*/
public class ConcreteStrategyC extends Strategy
/**
* 算法 C 实现
*/
@Override
public void algorithmInterface()
System.out.println("算法 C 实现");
Context,用一个 ConcreteStrategy 来配置,维护一个对 Strategy 对象的引用
/**
* 上下文
*/
public class Context
private Strategy strategy;
public Context()
/**
* 初始化时传入具体的策略对象
* @param strategy 具体的策略对象
*/
public Context(Strategy strategy)
this.strategy = strategy;
/**
* 上下文接口
*/
public void contextInterface()
strategy.algorithmInterface();
调用方代码
public class StrategyTest
/**
* 因为实例化不同的策略,所以在调用 context.contextInterface(); 时,得到的结果不同
*/
public static void main(String[] args)
Context context;
context = new Context(new ConcreteStrategyA());
context.contextInterface();
context = new Context(new ConcreteStrategyB());
context.contextInterface();
context = new Context(new ConcreteStrategyC());
context.contextInterface();
3、策略模式优缺点
优点:
- 由于策略类实现的是同一个抽象,策略类之间可以自由切换
- 对扩展开放,可以不改动原有代码,增加一个新的策略对策略模式来说比较容易
缺点:
- 维护策略类会有额外开销,策略类数量多了的话会比较麻烦
- 必须对调用方暴露所有的策略类,因为使用哪种策略由调用方决定,调用方需要了解每种策略及它们之间的区别
4、策略模式的应用场景
- 几个类的主要逻辑相同,只是部分逻辑的算法和行为上有一些区别的情况
- 有几种相似的行为,客户端动态的决定使用哪种,我们可以使用策略模式将算法封装起来供客户端使用
5、策略模式案例实现
商场收银
比如商场使用现金收银时,有正常收费 CashNormal、打折收费 CashRebate、和返利收费 CashReturn 三个策略,也就是策略模式中的具体算法,我们使用策略模式来做这样一个设计
代码结构图
现金收费抽象类
/**
* 抽象现金策略,收取现金,返回价格
*/
public abstract class CashStrategy
/**
* 接收现金
* @param money 接收的现金金额
* @param moneyRebate 打折率
* @param moneyCondition 返利条件
* @param moneyReturn 返利值
* @return 最后的金额
*/
public abstract BigDecimal acceptCash(BigDecimal money, Double moneyRebate, Double moneyCondition, Double moneyReturn);
/**
* 策略类型
* @return 策略类型
*/
public abstract String type();
正常收费策略
/**
* 正常收费子类,原价返回
*/
@Component
public class CashNormalStrategy extends CashStrategy
@Override
public BigDecimal acceptCash(BigDecimal money, Double moneyRebate, Double moneyCondition, Double moneyReturn)
return money;
@Override
public String type()
return "normal";
打折收费策略
/**
* 打折收费算法,初始化传入折扣,返回打折后金额
*/
@Component
public class CashRebateStrategy extends CashStrategy
@Override
public BigDecimal acceptCash(BigDecimal money, Double moneyRebate, Double moneyCondition, Double moneyReturn)
return money.multiply(BigDecimal.valueOf(moneyRebate > 0 ? moneyRebate : 1.0d)).setScale(2);
@Override
public String type()
return "rebate";
返利收费策略
/**
* 返利收费算法,初始化传入返利条件和返利值
*/
@Component
public class CashReturnStrategy extends CashStrategy
@Override
public BigDecimal acceptCash(BigDecimal money, Double moneyRebate, Double moneyCondition, Double moneyReturn)
BigDecimal result = money;
BigDecimal condition = BigDecimal.valueOf(moneyCondition == null ? 300.0d : moneyCondition);
BigDecimal returnMoney = BigDecimal.valueOf(moneyReturn == null ? 100.0d : moneyReturn);
// 如果大于返利条件,要减去返利值
if (money.compareTo(condition) > -1)
result = money.subtract(money.divideAndRemainder(condition)[0].multiply(returnMoney));
return result.setScale(2);
@Override
public String type()
return "return";
现金收费决策,根据类型选择策略
/**
* 现金策略决策,根据策略类型获取不同策略
*/
@Component
public class CashStrategyDecider
@Resource
private CashNormalStrategy normalStrategy;
@Resource
private CashRebateStrategy rebateStrategy;
@Resource
private CashReturnStrategy returnStrategy;
public CashStrategy decideCashStrategy(String strategyType)
if (strategyType == null )
return normalStrategy;
if (strategyType.equals(rebateStrategy.type()))
return rebateStrategy;
else
// todo 扩展点
if (strategyType.equals(returnStrategy.type()))
return returnStrategy;
return normalStrategy;
调用代码:
public class CashStrategyTest extends BaseTest
@Resource
private CashStrategyDecider cashStrategyDecider;
@Test
public void cashStrategyTest()
CashStrategy cashStrategy;
// 默认算法
cashStrategy = cashStrategyDecider.decideCashStrategy("");
BigDecimal defaultResult = cashStrategy.acceptCash(new BigDecimal(200), null, null, null);
System.out.println("使用默认算法得到的金额为" + defaultResult.doubleValue()); // 使用默认算法得到的金额为200.0
// 打折算法
cashStrategy = cashStrategyDecider.decideCashStrategy("rebate");
BigDecimal rebateResult = cashStrategy.acceptCash(new BigDecimal(200), 0.8d, null, null);
System.out.println("使用打折算法得到的金额为" + rebateResult.doubleValue()); // 使用打折算法得到的金额为160.0
// 返利算法
cashStrategy = cashStrategyDecider.decideCashStrategy("return");
BigDecimal returnResult = cashStrategy.acceptCash(new BigDecimal(500), null, 300d, 100.0d);
System.out.println("使用返利算法得到的金额为" + returnResult.doubleValue()); // 使用返利算法得到的金额为400.0
6、策略模式解析
- 策略模式是一种定义一系列算法的方法,从概念上来看,这些所有的算法完成的都是相同的工作,只是实现不同,它可以以相同的方式调用所有的算法,减少了各种算法类与使用算法类之间的耦合
- 对于打折、返利或者其它算法,其实都是对实际商品收费的一种计算方式,通过继承就可以得到它们的公共功能,这就让它们有了抽象的父类 CashStrategy
- 策略模式简化了单元测试,每个算法都有自己的类,可以通过自己的接口单独测试,每个算法可以保证它没有错误,修改其中一个也不会影响其它算法
- 策略模式封装了变化,只要在分析过程中听到需要在不同时间应用不同的业务规则,就可以考虑使用策略模式处理这种变化的可能性
- 基本的策略模式中,选择所用具体实现的职责由客户端对象承担,并转给策略模式的 Context 对象,相对来说比较好的办法是选择具体实现的职责也由 Context 来承担
以上是关于设计模式之策略模式(行为型)的主要内容,如果未能解决你的问题,请参考以下文章