设计模式-策略模式
概念
策略模式定义了一系列算法,所有这些算法从抽象概念上是相同的,只是实现不同,可以以相同方式(如相同签名的方法)调用;减少客户端掌握方法的数量以及减少各自算法类已使用算法类之间的耦合
优点
1、 策略模式提供了管理相关的算法族的办法。策略类的等级结构定义了一个算法或行为族。恰当使用继承可以把公共的代码转移到父类里面,从而避免重复的代码。
2、 策略模式提供了可以替换继承关系的办法。继承可以处理多种算法或行为。如果不是用策略模式,那么使用算法或行为的环境类就可能会有一些子类,每一个子类提供一个不同的算法或行为。但是,这样一来算法或行为的使用者就和算法或行为本身混在一起。决定使用哪一种算法或采取哪一种行为的逻辑就和算法或行为的逻辑混合在一起,从而不可能再独立演化。继承使得动态改变算法或行为变得不可能。
3、 使用策略模式可以避免使用多重条件转移语句。多重转移语句不易维护,它把采取哪一种算法或采取哪一种行为的逻辑与算法或行为的逻辑混合在一起,统统列在一个多重转移语句里面,比使用继承的办法还要原始和落后。
缺点
1、客户端必须知道所有的策略类,并自行决定使用哪一个策略类。这就意味着客户端必须理解这些算法的区别,以便适时选择恰当的算法类。换言之,策略模式只适用于客户端知道所有的算法或行为的情况。
2、 策略模式造成很多的策略类,每个具体策略类都会产生一个新类。有时候可以通过把依赖于环境的状态保存到客户端里面,而将策略类设计成可共享的,这样策略类实例可以被不同客户端使用。换言之,可以使用享元模式来减少对象的数量。
使用场景
1、如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为。
2、一个系统需要动态地在几种算法中选择一种。
3、如果一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句来实现。
角色
抽象策略角色: 策略类,通常由一个接口或者抽象类实现。
具体策略角色:包装了相关的算法和行为。
环境角色:持有一个策略类的引用,最终给客户端调用。
UML类结构图
以代码和文字说明解析类结构图
抽象策略角色
类:AbstarctStrategy
代码:
/** * Created by laizhiyuan on 2017/6/1. * * 设计模式-策略模式-抽象策略/算法 */ public abstract class AbstarctStrategy { /** * 计算金额抽象接口 * @param money * @return */ public abstract double countMoney(double money); /** * 不属于策略模式关键部分,我额外定义对参数进行检查的方法 * 检查金额 * @param money * @return */ protected double checkMoney(double money){ if (money == 0){ //TODO 处理为0时逻辑 } return money; } }
具体策略角色
类:EightFoldStrategy FiveFoldStrategy ThreeHundredToFiftyStrategy
代码:
/** * Created by Dell on 2017/6/1. * * 设计模式-策略模式-策略实现-八折策略 */ public class EightFoldStrategy extends AbstarctStrategy { /** * 策略实现 * @param money * @return */ @Override public double countMoney(double money) { checkMoney(money); double resultCount = money * 0.8; return resultCount; } }
/** * Created by laizhiyuan on 2017/6/1. * * 设计模式-策略模式-策略实现-五折策略 */ public class FiveFoldStrategy extends AbstarctStrategy{ /** * 策略实现 * @param money * @return */ @Override public double countMoney(double money) { checkMoney(money); double resultCount = money * 0.5; return resultCount; } }
/** * Created by laizhiyuan on 2017/6/1. * * 设计模式-策略模式-策略实现-满三百送五十折扣策略 */ public class ThreeHundredToFiftyStrategy extends AbstarctStrategy{ /** * 策略实现 * @param money * @return */ @Override public double countMoney(double money) { checkMoney(money); return money - StrategyHelper.getRebate(money, 300, 50); } }
环境角色
类:ContextStrategy
代码:
/** * 策略上下文类 * 何为上下文,就是实例化后拥有你需要使用哪个策略的信息 * 所以构造它时必须告诉你要使用哪个策略 * * Created by laizhiyuan on 2017/6/1. */ public class ContextStrategy { private final AbstarctStrategy strategy; /** * 初始化时入参一个策略 * @param strategy */ public ContextStrategy(AbstarctStrategy strategy) { if (strategy == null){ throw new RuntimeException("instantiation ContextStrategy faild,Must choose a strategy"); } this.strategy = strategy; } /** * 可以定义一个枚举,入参时发送一个某个策略对应的枚举值 * @param type */ public ContextStrategy(int type){ switch (type){ //八折策略 case 8: strategy = new EightFoldStrategy(); break; //五折策略 case 5: strategy = new FiveFoldStrategy(); break; //满300减50策略 case 250: strategy = new ThreeHundredToFiftyStrategy(); break; default: throw new RuntimeException("instantiation ContextStrategy faild,Must choose a strategy"); } } /** * 执行策略 * @param money * @return */ public double excuteStrategy(double money){ /** * 这里是根据优惠折扣算法计算金额 */ return strategy.countMoney(money); } }
工具类:
/** * Created by laizhiyuan on 2017/6/1. * * 这个实体在策略模式中不是必须的,可以按具体需求实现,也可以没有 * 在这里这个只是工具类,抽象之,不可实例化 * 设计模式-策略模式-折扣策略助手 * */ public abstract class StrategyHelper { /** * 获得返利金额 * @param totalMoney 总金额 * @param conditionMoney 满多少 * @param rebateMoney 送多少 * @return */ public static final double getRebate(double totalMoney, double conditionMoney, double rebateMoney){ if (totalMoney == 0){ return 0; } if (totalMoney < conditionMoney){ return totalMoney; } int multiple = (int) Math.floor(totalMoney / conditionMoney); return multiple * rebateMoney; } }
测试
/** * Main方法测试 * * Created by laizhiyuan on 2017/6/1. */ public class Main { private static ContextStrategy strategy; private static final double MONEY = 1000; private static double finalMoney = 0.0; public static void main(String[] args) { teseEightFoldStrategy(); teseFiveFoldStrategy(); teseThreeHundredToFiftyStrategy(); } /** * 测试五折策略 */ public static void teseFiveFoldStrategy(){ strategy = new ContextStrategy(new FiveFoldStrategy()); finalMoney = strategy.excuteStrategy(MONEY); System.out.println(MONEY + "五折后需付" + finalMoney); } /** * 测试八折策略 */ public static void teseEightFoldStrategy(){ strategy = new ContextStrategy(new EightFoldStrategy()); finalMoney = strategy.excuteStrategy(MONEY); System.out.println(MONEY + "八折后需付" + finalMoney); } /** * 测试满300退50 */ public static void teseThreeHundredToFiftyStrategy(){ strategy = new ContextStrategy(new ThreeHundredToFiftyStrategy()); finalMoney = strategy.excuteStrategy(MONEY); System.out.println(MONEY + "满300退50时需付" + finalMoney); } }