策略模式

定义:它定义了算法家族,分别封装起来,让他们之间可以相互替换,此模式让算法的变化,不会影响到使用算法的客户。

单看定义,是不是觉得有点虚,让我们通过生活中的例子来走进策略模式。

场景:商场收银的促销,打折或者返利的一个收银系统。

    private double getResult(String choose, String price, String num){
        double totalPrices;
        switch (choose){
            //不打折
            case "0":
                totalPrices = Double.valueOf(price)*Double.valueOf(num);
                break;
             //八折
            case "1":
                totalPrices = Double.valueOf(price)*Double.valueOf(num)*0.8;
                break;
            //七折
            case "2":
                totalPrices = Double.valueOf(price)*Double.valueOf(num)*0.7;
                break;
            default:
                throw new IllegalStateException("Unexpected value: " + choose);
        }
        return totalPrices;
    }

这样,一个简单的商场价格系统就设计出来了。但是仔细看代码,又出现了2个问题。1.有太多的重构代码,比如Double.valueof。2.如果增加需求,满300-20功能,又要改代码。这时候是不是想起来简单工厂模式。设计一个父类,然后不同的计算方式充当他的子类。虽然简单工厂模式是能解决这个问题。但是如果增加新的需求呢,满500-50这些。这样我们又要增加一个子类,工厂类也需要相应的改动。这种写法是不是不太合适,在简单工厂模式中,工厂类是暴露给用户的,你经常改动工厂类是不合适的,所以这时候简单工厂并不合适,所以引入策略模式。

 

//抽象算法类
public interface Strategy {
    //算法方法
    public abstract void AlgorithmInterface();
}
//封装了具体的算法或行为
public class ConcreteStrategyA extends Strategy{
    @Override
    public void AlgorithmInterface() {
        System.out.println("算法A实现");
    }
}
public class ConcreteStrategyB extends Strategy{
    @Override
    public void AlgorithmInterface() {
        System.out.println("算法B实现");
    }
}

Context,用一个ConcreteStrategy来配置,维护一个对Strategy对象的引用。

    Strategy strategy;
    //构造函数,初始化时传入具体的策略对象
    public Context(Strategy strategy){
        this.strategy = strategy;
    }
    //根据具体的策略对象,调用其算法的方法
    public void ContextInterface(){
        strategy.AlgorithmInterface();
    }

调用方法:

    public static void main(String[] args) {
        Context context;
        context = new Context(new ConcreteStrategyA());
        context.ContextInterface();

        context = new Context(new ConcreteStrategyB());
        context.ContextInterface();
    }

以上就是策略模式的基本逻辑。现在我们就来写写商场系统的策略模式。

public abstract class CashSuper {
    public abstract double acceptCash(double money);
}
//正常收费
public class CashNormal extends CashSuper {
    @Override
    public double acceptCash(double money) {
        return money;
    }
}
//打折类
public class CashRebate extends CashSuper {
    private double moneyRebate = 1d;

    public CashRebate(String moneyRebate){
        this.moneyRebate =Double.valueOf(moneyRebate) ;
    }
    @Override
    public double acceptCash(double money) {
        return money*moneyRebate;
    }
}
//满减类
public class CashReturn extends CashSuper {
    private double moneyCondition = 0.0d;
    private double moneyReturn = 0.0d;
    public CashReturn(String moneyCondition , String moneyReturn){
        this.moneyCondition =Double.valueOf(moneyCondition) ;
        this.moneyReturn = Double.valueOf(moneyReturn);
    }
    @Override
    public double acceptCash(double money) {
        double result = money;
        if (money>= moneyCondition){
            return money-Math.floor(money/moneyCondition)*moneyReturn;
        }
        return result;
    }
}

管理

public class CashContext {
    private CashSuper cs;
    public CashContext(CashSuper csper){
        this.cs = csper;
    }
    public double getResult(double money){
        return cs.acceptCash(money);
    }
}
    private double getResult1(String choose, String price, String num){
        CashContext cashContext;
        switch (choose){
            //不打折
            case "正常收费":
                cashContext = new CashContext(new CashNormal());
                break;
            case "满300-30":
                cashContext = new CashContext(new CashReturn("300","30"));;
                break;
            case "满八折":
                cashContext = new CashContext(new CashRebate("0.8"));;
                break;
            default:
                throw new IllegalStateException("Unexpected value: " + choose);
        }
        double totalPrices = 0d;
        totalPrices = cashContext.getResult(Double.valueOf(price)*Double.valueOf(num));
        return totalPrices;
    }

但是这种写法你不觉得怪怪的嘛,类的生成还是通过客户端去选择,这和我们的简单工厂模式很类似。所以我们就需要将策略模式和简单工厂模式结合。

public class CashContext {
    private CashSuper cs;
    public CashContext(String type){
        switch (type){
            //不打折
            case "正常收费":
                cs = new CashNormal();
                break;
            case "满300-30":
                cs = new CashReturn("300","30");
                break;
            case "满八折":
                cs = new CashRebate("0.8");;
                break;
            default:
                throw new IllegalStateException("Unexpected value: " + type);
        }

    }
    public double getResult(double money){
        return cs.acceptCash(money);
    }
    private double getResult1(String choose, String price, String num){
        CashContext cashContext;
        cashContext = new CashContext("满300-30");//选择方式
        double totalPrices = 0d;
        totalPrices = cashContext.getResult(Double.valueOf(price)*Double.valueOf(num));
        return totalPrices;
    }

你看,这种写法是不是比之前好多了。相比于工厂模式,客户端需要认识CashSupe和CashFactory,而现在客户端只需要认识CashContext,大大的降低了耦合度。

 

总结一下,什么叫做策略模式:

1.策略模式是一种定义一系列算法的方法,这些算法完成的都是相同的工作(都是打折、满减、正常)这些,只不过实现不一样,但是可以用相同的方式调用所有的方法,减少了算法之间的耦合。

 

上一篇:如何使用PXE实现Linux网络装机


下一篇:Python学习笔记(二):数据类型