策略模式(Strategy):它定义了算法家族,分别封装起来,让它们可以互相兑换,此模式让算法的变化不会影响到使用算法的客户。
策略模式就是用来封装算法的,但在实践中,我们发现可以用它来封装几乎任何类型的规则,只要在分析过程中需要在不同实践应用不同的业务规则,就可以考虑用策略模式。
策略模式UML:
超市收费示例:
//策略接口
public interface CashierAlg {
//输入总消费,然后根据不同的活动得到不同的金额
public double getMoney(double Money);
}
策略实现类:
//打折
public class Discount implements CashierAlg{
private double count;
public Discount(double count) {
super();
this.count = count;
}
@Override
public double getMoney(double Money) {
// TODO Auto-generated method stub
return Money*this.count;
}
//不打折
public class NoDiscount implements CashierAlg{
@Override
public double getMoney(double Money) {
// TODO Auto-generated method stub
return Money;
}
}
上下文类
/*
* 上下文类
*/
public class ContextStrategy {
private CashierAlg cash;
public ContextStrategy(CashierAlg cash) {
this.cash = cash;
}
public double getResult(double Money)
{
//调用不同的策略
return cash.getMoney(Money);
}
}
测试类:
public class TestMain {
public static void main(String[] args) {
String a = new Scanner(System.in).nextLine();
ContextStrategy con = null;
switch (a) {
case "不打折":
con = new ContextStrategy(new NoDiscount());
break;
case "打8折":
con = new ContextStrategy(new Discount(0.8));
break;
default:
break;
}
System.out.println(con.getResult(100));
}
}
在示例代码中,商场需要根据不同的活动计算出顾客不同的花费,因此我们采用了策略模式,通过调用context类调用不同的算法。但是示例中还有缺点,就是测试类中出现了判断语句,代码比较长,因此我们可以将策略模式和简单工厂模式结合,将判断语句移动到context类中。
Context改变如下:
/*
* 策略模式与简单工厂模式结合
*/
public class ContextStrategyAndSimFact {
private CashierAlg cs;
public ContextStrategyAndSimFact(String type)
{
switch (type) {
case "不打折":
this.cs = new NoDiscount();
break;
case "打8折":
this.cs = new Discount(0.8);
break;
default:
break;
}
}
public double getResult(double Money)
{
return cs.getMoney(Money);
}
}
测试类
public class TestMain2 {
public static void main(String[] args) {
ContextStrategyAndSimFact con = new ContextStrategyAndSimFact("打8折");
System.out.println(con.getResult(100));
}
}
由此可见,当与简单工厂模式结合之后,测试类的代码简洁了很多。策略模式的Strategy类层次为Context定义了一系列的可供重用的算法和行为,继承有助于吸取这些算法中的公共功能。
另外策略模式简化了单元测试,因为每个算法都有自己的类,可以通过接口单独测试这些算法