基础的策略模式
策略模式(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都不让客户端认识了。
策略模式是一种定义一系列算法的方法,从概念上来看,所有这些算法完成的都是相同的工作,只是实现的不同,它可以以相同的方式调用所有的算法,减少了各种算法类与使用算法类之间的耦合。
这样每个算法可保证他没有错误,修改其中任意一个时也不会影响其他的算法,
策略模式封装了变化。
策略模式就是用来封装算法的,但在实践中,我们发现可以用它来封装几乎任何类型的规则,只要在分析过程中听到需要在不同时间应用不同的业务规则,就可以考虑使用策略模式处理这种变化的可能性。
其实还有更加优化的方法。使用反射技术。之后我在讲。