基础的策略模式

策略模式(Strategy):它定义了算法家族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化,不会影响到使用算法的客户。
比如:一个商场正在搞促销,有打八折的,有按正常价位收取的,七折,五折,满300减100,满200送50…
其实商场收银时如何促销,用打折还是返利,其实都是一些算法。
不管是打折,返利,都是一种现金收费的一种方式。
首先要有一个现金收费的接口:

//现金收取的接口
public interface CashSuper {
    //收取现金,参数是原价,返回的是当前价
    double acceptCash(double money);
}

具体的收费方式:
1.原价收费

//正常收费子类
public class CashNormal implements CashSuper {
    //正常收费,返回原价
    @Override
    public double acceptCash(double money) {
        return money;
    }
}

2,打折

//打折收费子类
public class CashRebate implements CashSuper {
    //打折收费,需要折扣率
    private double moneyRebate = 1d;
    public CashRebate(){}
    //构造方法初始化折扣
    public CashRebate(double moneyRebate){
        this.moneyRebate = moneyRebate;
    }
    @Override
    //打折收费,返回折扣之后的价格
    public double acceptCash(double money) {
        return money*moneyRebate;
    }
}

3.返利:

//返利收费子类
public class CashReturn implements CashSuper {
    //返利达到的条件
    private double moneyCondition = 0d;
    //返利的值
    private double moneyReturn = 0d;
    //构造方法
    public CashReturn(){}
    //初始化返利条件和返利的值
    public CashReturn(double moneyCondition,double moneyReturn){
        this.moneyCondition = moneyCondition;
        this.moneyReturn = moneyReturn;
    }
    @Override
    public double acceptCash(double money) {
        if(money>=moneyCondition){
            money=money-moneyReturn;
        }
        return money;
    }
}

然后又可以把具体的收费方式看成一种收费的具体策略,所以可以把他门封装在一个类中。
设计一个收费策略类:

public class CashContext {
    //声明一个CashSuper对象
    private CashSuper cash;
    public CashContext(){}
    //通过构造方法传入具体的收费策略
    public CashContext(CashSuper cash){
        this.cash = cash;
    }
    public double GetResult(double money){
        //根据收费的策略的不同,获得计算结果
        return cash.acceptCash(money);
    }
}

最后就是一个客户类:

//客户
public class Client {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        //应该花费的价格
        double total = 0d;
        //声明CashContext对象
        CashContext cashContext = null;
        System.out.println("---------欢迎来到购物商场---------");
        System.out.println("请输入该物品的价格:");
        total = input.nextDouble();
        System.out.println("-----1.原价 2.打折 3.返利--------");
        System.out.println("请输入选择的优惠的方式:");
        int num = input.nextInt();
        switch (num){
            case 1 :
                cashContext = new CashContext(new CashNormal());
                break;
            case 2 :
                cashContext = new CashContext(new CashRebate(0.8));
                break;
            case 3 :
                cashContext = new CashContext(new CashReturn(300,100));
                break;
            default:
                System.out.println("输入错误...");
                break;
        }
        total = cashContext.GetResult(total);
        System.out.println("你实际支付的价格为:"+total+"元");
    }
}

这样就是一个基础的策略模式,把收费的策略封装在了一个类中,但是这样就会变成由客户端去判断是哪一种收费算法,这样就非常的不合适。因为这样客户就可以知道CashContext,CashNormal,CashRebate,CashReturn这些类,耦合很高。所以我们可以优化一下,把简单工厂和策略模式结合在一块。

策略模式和简单工厂模式结合

CashContext:

public class CashContext1 {
    private CashSuper cashSuper;
    //构造方法得到是那种收费方式
    public CashContext1(int mode){
        switch (mode){
            case 1 :
               cashSuper = new CashNormal();
                break;
            case 2 :
                cashSuper = new CashRebate(0.8);
                break;
            case 3 :
                cashSuper = new CashReturn(300,100);
                break;
            default:
                System.out.println("输入错误...");
                break;
        }
    }
    public double GetResult(double money){
        //根据收费的策略的不同,获得计算结果
        return cashSuper.acceptCash(money);
    }
}

客户端:

public class Client1 {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        //应该花费的价格
        double total = 0d;
        //声明CashContext对象
        CashContext1 cashContext = null;
        System.out.println("---------欢迎来到购物商场---------");
        System.out.println("请输入该物品的价格:");
        total = input.nextDouble();
        System.out.println("-----1.原价 2.打折 3.返利--------");
        System.out.println("请输入选择的优惠的方式:");
        int num = input.nextInt();
        cashContext = new CashContext1(num);
        total=cashContext.GetResult(total);
        System.out.println("你实际支付的价格为:"+total+"元");

    }
}

这样就可以看出,客户端就只需要认识一个类,CashContext就可以了,耦合更加低了。在客户端实例化的是CashContext的对象,调用的是CashContext的方法GetResult,这使得具体的收费算法彻底和客户端分离,连算法的父类CashSuper都不让客户端认识了。

策略模式是一种定义一系列算法的方法,从概念上来看,所有这些算法完成的都是相同的工作,只是实现的不同,它可以以相同的方式调用所有的算法,减少了各种算法类与使用算法类之间的耦合。
这样每个算法可保证他没有错误,修改其中任意一个时也不会影响其他的算法,

策略模式封装了变化。

策略模式就是用来封装算法的,但在实践中,我们发现可以用它来封装几乎任何类型的规则,只要在分析过程中听到需要在不同时间应用不同的业务规则,就可以考虑使用策略模式处理这种变化的可能性。
其实还有更加优化的方法。使用反射技术。之后我在讲。