策略模式
来源:互联网 发布:任务管理 知乎 编辑:程序博客网 时间: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);
}
}
简单工厂实现
需求变更:周年庆,打八折;满300送100
//现金收费抽象类
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);
}
}
策略模式
需求变更:这时需要打五折和满500送200,解决方案,在收费对象生成工厂类中的switch中再加两个分支;增加一种新的商场促销手段满100积分送20积分,积分到一定程度可以领取奖品,解决办法,新增一个积分算法类(构造方法有两个参数,条件和返点),继承ChargeSuper类,在收费对象生成工厂中添加满100积分送20积分的分支条件
需求变更问题:商场可能经常性的更改打折额度和返利额度,每次扩展和维护收费方式都要更改工厂,以致代码需要重新编译部署,麻烦.
策略模式:定义了算法家族,分别封装起来,让它们之间可以相互替换,此模式让算法的变化,不会影响到使用算法的用户.商场收银时如何促销,用打折还是返利,其实都是一些算法,用工厂来生成算法对象,没错,但是算法本身只是一种策略,算法随时有可能互相替换,这就是变化点,而封装变化点是我们面向对象的一种很重要的思维
上面简单工厂实现的ChargeSuper就是抽象策略,和正常收费ChargeNormal,打折收费ChargeRebate和返利收费ChargeReturn就是三个具体策略,也就是策略中的具体算法.原本写的ChargeSuper,ChargeNormal,ChargeRebate,ChargeReturn都不用更改,只需要加一个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);
}
}
总结:
①通过构造器给属性(父类引用)赋值的方式,构造器的形参是判断的条件,根据条件的不同来创建合适的子类对象,并指向父类引用(多态)
②简单工厂模式中的测试类中出现了两个类:ChargeSuper和ChargeFactory,而策略模式和简单工厂结合的测试类中只出现了一个类ChargeContext,耦合度更加降低
策略模式的好处:
①策略模式是一种定义了一系列算法的方法,所有的算法都是完成相同的工作,只是实现不同,它可以以相同的方式调用相同的算法,减少了各种算法和算法使用类的耦合
②策略模式的父类为Context定义了一系列可供重用的算法和行为.继承有助于提取出这些算法的公共功能(本例中的公共功能就是getToatlPrice)
③策略模式简化了单元测试,每个算法都有自己的类(修改算法不会影响其他),可以通过自己的接口单独测试
扩展:
①策略模式是用来封装算法的,但在实践中,可以用它来封装几乎任何类型的规则,只要在分析过程中听到需要在不同时间应用不同的规则,就可以考虑使用策略模式处理这种变化的可能性
②但是在ChargeContext中还是用到了switch,也就是说,如果我们还需要增加一种算法,比如满200减200,还得更改switch中的代码,不爽!可以用反射解决,详情请见以后的抽象工厂模式
- 策略模式
- 策略模式
- 策略模式
- 策略模式
- 策略模式
- 策略模式
- 策略模式
- 策略模式
- 策略模式
- 策略模式
- 策略模式
- 策略模式
- 策略模式
- 策略模式
- 策略模式
- 策略模式
- 策略模式
- 策略模式
- SQL常用语句
- Springboot 整合 Dubbo/ZooKeeper 详解 SOA 案例
- Could not initialize class sun.awt.X11GraphicsEnvironment linux中影像缩略图
- 计算1+3+5+...+99+101的值
- spring boot实战(第八篇)上下文的创建
- 策略模式
- n元语法
- 页面数据库特殊字符处理
- maven错误
- 单一职责原则
- [leetcode]#160. Intersection of Two Linked Lists
- Grafana+Prometheus打造全方位立体监控系统
- kettle 数据同时插入删除问题
- spring boot实战(第九篇)Application创建源码分析