策略模式

来源:互联网 发布:任务管理 知乎 编辑:程序博客网 时间:2024/05/19 18:37

策略模式

//根据单价和数量计算总价

public class Charge {

public static  double getTotalPrice(double unitPrice, int number) {

double totalPrice = 0;

totalPrice = unitPrice * number;

return totalPrice;

}

public static void main(String[]args) {

Scanner sc=new Scanner(System.in);

System.out.println("请输入购买数量");

int number =sc.nextInt();

System.out.println("请输入商品价格");

double unitPrice =sc.nextDouble();

double totalPrice =Charge.getTotalPrice(unitPrice, number);

System.out.println("商品价格为");

System.out.println(totalPrice);

}

}

简单工厂实现

需求变更:周年庆,打八折;300100

//现金收费抽象类

public abstract class ChargeSuper {

//收取现金的方法参数为原价返回值为现价

public abstract double charge(double money);

}

//正常收费子类

public class ChargeNormal extends ChargeSuper{

//正常收费原价返回

public double charge(double money) {

return money;

}

}

//打折收费子类

public class ChargeRebate extends ChargeSuper {

//折扣率属性比如八折就是0.8

private double moneyRebate;

public ChargeRebate(double moneyRebate) {

this.moneyRebate =moneyRebate;

}

public double charge(double money) {

return money*moneyRebate;

}

}

//返利收费子类

public class ChargeReturn extends ChargeSuper {

//满moneyCondition返moneyReturn

private double moneyCondition;

private double moneyReturn;

public ChargeReturn(double moneyCondition, double moneyReturn) {

this.moneyCondition =moneyCondition;

this.moneyReturn =moneyReturn;

}

public double charge(double money) {

if(money>=moneyCondition) {

//如果大于返利条件需要剪去返利值

money=money-Math.floor(money/moneyCondition)*moneyReturn;

}

return money;

}

}

//收费对象生成工厂类和测试

public class ChargeFactory {

public static ChargeSuper createChargeSuper(String type) {

ChargeSuper cs=null;

switch (type) {

case "正常收费":

cs=new ChargeNormal();

break;

case "满300减100":

cs=new ChargeReturn(300,100);

break;

case "打八折":

cs=new ChargeRebate(0.8);

break;

default:

break;

}

return cs;

}

public static void main(String[]args) {

ChargeSuper chargeSuper =ChargeFactory.createChargeSuper("正常收费");

double charge =chargeSuper.charge(600);

System.out.println(charge);

}

}

策略模式

需求变更:这时需要打五折和满500200,解决方案,在收费对象生成工厂类中的switch中再加两个分支;增加一种新的商场促销手段满100积分送20积分,积分到一定程度可以领取奖品,解决办法,新增一个积分算法类(构造方法有两个参数,条件和返点),继承ChargeSuper类,在收费对象生成工厂中添加满100积分送20积分的分支条件

需求变更问题:商场可能经常性的更改打折额度和返利额度,每次扩展和维护收费方式都要更改工厂,以致代码需要重新编译部署,麻烦.

策略模式:定义了算法家族,分别封装起来,让它们之间可以相互替换,此模式让算法的变化,不会影响到使用算法的用户.商场收银时如何促销,用打折还是返利,其实都是一些算法,用工厂来生成算法对象,没错,但是算法本身只是一种策略,算法随时有可能互相替换,这就是变化点,而封装变化点是我们面向对象的一种很重要的思维

上面简单工厂实现的ChargeSuper就是抽象策略,和正常收费ChargeNormal,打折收费ChargeRebate和返利收费ChargeReturn就是三个具体策略,也就是策略中的具体算法.原本写的ChargeSuperChargeNormalChargeRebateChargeReturn都不用更改,只需要加一个ChargeContext,并改写一下测试类

//维护对策略对象的引用

public class ChargeContext {

private ChargeSuper cs;

//通过构造方法传入具体的策略

public ChargeContext(ChargeSuper cs) {

this.cs =cs;

}

//根据收费策略的不同获得计算结果

public double getTotalPrice(double money) {

return cs.charge(money);

}

public static void main(String[]args) {

ChargeContext cs=null;

Scanner sc=new Scanner(System.in);

System.out.println("请输入购买数量");

int number =sc.nextInt();

System.out.println("请输入商品单价");

double unitPrice =sc.nextDouble();

System.out.println("请输入一个收费方式");

String type =sc.next();

switch (type) {

case "正常收费":

cs=new ChargeContext(new ChargeNormal());

break;

case "满300减100":

cs=new ChargeContext(new ChargeReturn(300,100));

break;

case "打八折":

cs=new ChargeContext(new ChargeRebate(0.8));

break;

default:

break;

}

//计算出原价

double money=number*unitPrice;

//得到现价

cs.getTotalPrice(money);

}

}

策略者模式和简单工厂模式很像,只不过策略者模式通过构造器给属性赋值的方式(构造器的形参是父类的引用)封装了子类对象指向父类引用(多态)的过程.但是多态的过程还是看到了ChargeContext和各种子类,耦合性较大

问题描述:还需要在测试类中判断用哪一个算法,如何将判断过程从测试类中转移走呢?请看下文,策略与简单工厂的结合

策略与简单工厂结合

public class ChargeContext2 {

ChargeSuper sc=null;

public ChargeContext2(String type) {

switch (type) {

case "正常收费":

sc=new ChargeNormal();

break;

case "满300减100":

sc=new ChargeReturn(300,100);

break;

case "打八折":

sc=new ChargeRebate(0.8);

break;

default:

break;

}

}

public double getTotalPrice(double money) {

return sc.charge(money);

}

public static void main(String[]args) {

Scanner sc=new Scanner(System.in);

System.out.println("请输入购买数量");

int number =sc.nextInt();

System.out.println("请输入商品单价");

double unitPrice =sc.nextDouble();

System.out.println("请输入一个收费方式");

String type =sc.next();

ChargeContext2 cc2=new ChargeContext2(type);

//计算出原价

double money=number*unitPrice;

//得到现价

double totalPrice =cc2.getTotalPrice(money);

System.out.println(totalPrice);

}

}

总结:

通过构造器给属性(父类引用)赋值的方式,构造器的形参是判断的条件,根据条件的不同来创建合适的子类对象,并指向父类引用(多态)

简单工厂模式中的测试类中出现了两个类:ChargeSuperChargeFactory,而策略模式和简单工厂结合的测试类中只出现了一个类ChargeContext,耦合度更加降低

策略模式的好处:

①策略模式是一种定义了一系列算法的方法,所有的算法都是完成相同的工作,只是实现不同,它可以以相同的方式调用相同的算法,减少了各种算法和算法使用类的耦合

策略模式的父类为Context定义了一系列可供重用的算法和行为.继承有助于提取出这些算法的公共功能(本例中的公共功能就是getToatlPrice)

策略模式简化了单元测试,每个算法都有自己的类(修改算法不会影响其他),可以通过自己的接口单独测试

扩展:

①策略模式是用来封装算法的,但在实践中,可以用它来封装几乎任何类型的规则,只要在分析过程中听到需要在不同时间应用不同的规则,就可以考虑使用策略模式处理这种变化的可能性

但是在ChargeContext中还是用到了switch,也就是说,如果我们还需要增加一种算法,比如满200200,还得更改switch中的代码,不爽!可以用反射解决,详情请见以后的抽象工厂模式

原创粉丝点击