以商场收银为例,理解并实践“策略模式”。
- 简单商场促销活动描述:营业员提供商品单价、数量、商场目前的活动(满减、打折等),计算用户最终需要支付的金额。
一、面向过程的实现方式
1 package secondStrategy; 2 import java.text.DecimalFormat; 3 public class StrategyTest { 4 public static void main(String[] args) { 5 // 营业员提供信息 6 double total=0; 7 double price=2; 8 int num=3; 9 String promotions="打8折";//或者“满100-30” 10 11 // 计算待付金额 12 double totalPrice=price*num; 13 total=total+totalPrice; 14 15 switch (promotions) { 16 case "打8折":total=total*0.8;break; 17 case "满100-30": total=total-(total/100)*30; // "/"取整。“%”取余 18 default: 19 break; 20 } 21 DecimalFormat df = new DecimalFormat("#.##"); // 如果写成0.00,结果就一定是两个小数 22 System.out.println("单价:"+price+";数量:"+num+";原价:"+totalPrice+";活动:"+promotions+";活动价:"+df.format(total)); 23 24 } 25 }
缺点:当有新的活动时,就要不停地复制程序代码,新增一个类别,这使程序的重复性增加,可维护性变差。
二、通过简单工厂实现
1、UML图结构
2、语言描述
- 父类:现金收费抽象类CashSuper
- 抽象方法:acceptCash( 原价){ return 活动价}
- 子类:正常收费CashNormal、
- 实现父类抽象方法:acceptCash( 原价){ return 原价}
- 子类:打折类CashRebate
- 私有属性:moneyRebate;
- 构造方法:带moneyRebate的
- 实现父类抽象方法:acceptCash( 原价){ return 原价*moneyRebate}
- 子类:满减类CashRerurn
- 私有属性:moneyCondition; moneyReturn;
- 构造方法:带上面俩参数的
- 实现父类抽象方法:acceptCash( 原价){ return 原价-满减价}
- 工厂:CashFactory
- createCashAccept( String type)
- 客户端:price/ num / "活动type"
- 实例化
- 输出
三、通过策略模式来设计
1、UML图结构
2、文字描述
- 父类策略类:CashSuper
- 抽象方法:acceptCash( 原价){ return 活动价}
- 具体策略子类1:正常收费CashNormal、
- 实现父类抽象方法:acceptCash( 原价){ return 原价}
- 具体策略子类2:打折类CashRebate
- 私有属性:moneyRebate;
- 构造方法:带moneyRebate的
- 实现父类抽象方法:acceptCash( 原价){ return 原价*moneyRebate}
- 具体策略子类3:满减类CashRerurn
- 私有属性:moneyCondition; moneyReturn;
- 构造方法:带上面俩参数的
- 实现父类抽象方法:acceptCash( 原价){ return 原价-满减价}
- Context类:CashContext
- 私有属性:CashSuper cs;
- 构造方法:CashContext( CashSuper csuper){ this....}
- 取得金额方法: getResult(){ cs.acceptCash()}
- 客户端:price/ num / "活动type"
- switch(type) : cc=new CashContext( new CashRebate( canshu1, canshu2))
- cc.getResult()
四、策略模式与工厂模式相结合
1、UML图结构
2、文字描述
- 父类策略类:CashSuper
- 抽象方法:acceptCash( 原价){ return 活动价}
- 具体策略子类1:正常收费CashNormal、
- 实现父类抽象方法:acceptCash( 原价){ return 原价}
- 具体策略子类2:打折类CashRebate
- 私有属性:moneyRebate;
- 构造方法:带moneyRebate的
- 实现父类抽象方法:acceptCash( 原价){ return 原价*moneyRebate}
- 具体策略子类3:满减类CashRerurn
- 私有属性:moneyCondition; moneyReturn;
- 构造方法:带上面俩参数的
- 实现父类抽象方法:acceptCash( 原价){ return 原价-满减价}
- Context类:CashContext
- 私有属性:CashSuper cs;
- 构造方法:CashContext( String type){ switch()}
- 取得金额方法: getResult(){ cs.acceptCash()}
- 客户端:price/ num / "活动type"
- new CashContext( type )
3、java代码实现
- 父类策略类:CashSuper
1 package secondStrategy; 2 3 public abstract class CashSuper { 4 public abstract double acceptCash(double money); 5 }
-
- 具体策略子类1:正常收费CashNormal
1 package secondStrategy; 2 3 public class CashNormal extends CashSuper { 4 5 @Override 6 public double acceptCash(double money) { 7 return money; 8 } 9 10 }
-
- 具体策略子类2:打折类CashRebate
1 package secondStrategy; 2 3 // 打折类 4 public class CashRebate extends CashSuper { 5 private double moneyRebate=0; 6 // 构造方法,初始化时应传入折扣 7 public CashRebate(double moneyRe) { 8 this.moneyRebate=moneyRe; 9 } 10 @Override 11 public double acceptCash(double money) { 12 double result=0; 13 result=money*moneyRebate; 14 return result; 15 } 16 17 }
-
- 具体策略子类3:满减类CashRerurn
1 package secondStrategy; 2 3 public class CashReturn extends CashSuper { 4 private double moneyCondition=0; //满减门槛 5 private double moneyReturn=0; // 满减金额 6 7 public CashReturn(double moneyCon,double moneyRe) { 8 // TODO Auto-generated constructor stub 9 this.moneyCondition=moneyCon; 10 this.moneyReturn=moneyRe; 11 } 12 13 @Override 14 public double acceptCash(double money) { 15 double result=0; 16 result=money-(money/moneyCondition)*moneyReturn; 17 return result; 18 } 19 20 }
- Context类:CashContext
1 package secondStrategy; 2 3 public class CashContext { 4 private CashSuper cSuper; 5 public CashContext( String type) { 6 switch (type) { 7 case "打8折": this.cSuper=new CashRebate(0.8); break; 8 case "满100-30": this.cSuper=new CashReturn(100,30);break; 9 default:this.cSuper=new CashNormal(); 10 break; 11 } 12 } 13 public double getResult(double money){ 14 return this.cSuper.acceptCash(money); 15 } 16 }
- 客户端:
package secondStrategy; import java.text.DecimalFormat; public class StrategyTest { public static void main(String[] args) { // 营业员提供信息 double total=0; double price=2; int num=3; String promotions="打8折";//或者“满100-30” // 计算待付金额 double totalPrice=price*num; total=total+totalPrice; switch (promotions) { case "打8折":total=total*0.8;break; case "满100-30": total=total-(total/100)*30; // "/"取整。“%”取余 default: break; } DecimalFormat df = new DecimalFormat("#.##"); // 如果写成0.00,结果就一定是两个小数 System.out.println("单价:"+price+";数量:"+num+";原价:"+totalPrice+";活动:"+promotions+";活动价:"+df.format(total)); } }
运行结果:
五、总结说明
1、定义:策略模式是一种定义一系列算法的方法,从概念上看,所有这些算法完成的都是相同的工作,只是实现不同。它可以有相同的方式调用所有的算法,减少了各种算法类与使用算法类之间的耦合。
2、策略模式的Strategy类层次为Context定义了一系列可供重用的算法或行为。继承有助于析取出这些算法的公共功能——计费结果getResult()。
3、优点:
- 它可以有相同的方式调用所有的算法,减少了各种算法类与使用算法类之间的耦合。
- 简化了单元测试,因为每个算法都有自己的类,可以通过自己的接口单独测试。
4、特点:
- 策略模式就是用来封装算法的,但在实践中,发现可以用它来封装几乎任何类型的规则,只要在分析过程中听到需要在不同时间应用不同的业务规则,就可以考虑使用策略模式处理这种变化的可能性。
- 在基本的策略模式中,选择所用具体实现的职责有客户端对象承担,并转给策略模式的Context对象。本身虽然没有接触客户端需要选择判断的压力,但将简单工厂与策略模式结合之后,由Context来承担选择的工作,最大化地减轻了客户端的职责。
- 任何需求都是需要成本的,日后会讲到反射机制,可以不用选择,以后再说咯!
原文地址:https://www.cnblogs.com/zuolanlan/p/9990495.html
时间: 2024-10-08 13:23:06