文章目录
前言
做一个商场收银软件,营业员根据客户所购买商品的单价和数量,向顾客收费。
一、代码1.0
1.1. 代码
public class StrategyMode {
public static void main(String[] args) {
double total = 0;
//实际的price 和count可以做个界面,从框中取值
double price = 3;
int count = 5;
total = price * count;
System.out.println("商品合计总价:"+total);
}
}
实际可以做一个界面出来,用两个文本框输入单价和数量,一个确定按钮来算出每种商品的费用,用个列表框来记录商品的清单,一个标签来记录总数,一个按钮重新开始。
2.2. 存在的问题
如果要打八折,可以使用total*0.8,但是如果不打折了,需要重新修改一遍代码,或者打五折,都需要重新去修改代码。
二、代码1.1 增加打折
2.1. 代码
public class StrategyMode {
public static void main(String[] args) {
double total = 0;
//实际的price 和count可以做个界面,从框中取值
double price = 3;
int count = 5;
total = getTotal("打五折",price,count);
System.out.println("商品合计总价:"+total);
}
public static double getTotal(String type, double price, int count){
double totalPrice = 0;
switch (type){
case "正常收费":
totalPrice = price * count;
break;
case "打八折":
totalPrice = price * count * 0.8;
break;
case "打五折":
totalPrice = price * count * 0.5;
break;
}
return totalPrice;
}
}
2.2. 存在的问题
三个switch分支语句除了打折多少以外几乎没什么不同,应该考虑重构一下。
如果增加需求要满300-30,还得修改促销类型代码。
在这里可以使用简单工厂模式,先写一个父类,在继承它实现多个打折和返利的子类,利用多态来解决问题。
而且不用打五折、打八折、满300送30,满500送60都分别写一个类,可以将打折写一个类,返利写一个类。
三、代码2.0 使用简单工厂写打折类和返利类
打折基本上是一样得,只要有个初始化参数就可以了。返利需要两个参数。
面向对象编程并不是类越多越好,类得划分是为了封装,但分类得基础是抽象,具有相同属性和功能得对象得抽象集合才是类。
打八折和打五折只是形式不同,抽象分析出来,所有的打折算法都是一样的,所以打折算法是一个类。
3.1. 代码
//现金收取超类
public abstract class CashSuper {
//超类的抽象方法,收取现金,参数为原件,返回为当前价
public abstract double acceptCash(double money);
}
//无折扣正常收费类
public class CashNormal extends CashSuper{
@Override
//正常收费,返回原价
public double acceptCash(double money) {
return money;
}
}
//打折类
public class CashRebate extends CashSuper{
private double moneyRebate = 1;
public CashRebate(double moneyRebate){
this.moneyRebate = moneyRebate;
}
@Override
public double acceptCash(double money) {
return money * moneyRebate;
}
}
//返利类
public class CashReturn extends CashSuper{
//返利条件
private double moneyCondition = 0;
//返利值
private double moneyReturn = 0;
public CashReturn (double moneyCondition,double moneyReturn){
this.moneyCondition = moneyCondition;
this.moneyReturn = moneyReturn;
}
@Override
public double acceptCash(double money) {
if (money > moneyCondition){
return moneyCondition - moneyReturn;
}else {
return money;
}
}
}
//现金收费工厂类
public class CashFactory {
public static CashSuper createCashAccept(String type){
CashSuper cs = null;
switch (type){
case "正常收费":
cs = new CashNormal();
break;
case "打八折":
cs = new CashRebate(0.8);
break;
case "满300返100":
cs = new CashReturn(300,100);
break;
}
return cs;
}
}
客户程序主要部分:
public class StrategyMode {
public static void main(String[] args) {
CashSuper cs = CashFactory.createCashAccept("打八折");
double result = cs.acceptCash(88);
System.out.println("最后的金额为:"+result);
}
}
3.2. 存在的问题
如果需要打五折或者满500减60,需要在收费对象生成工厂增加两个条件。
如果需要增加另外一种促销方式,比如:满100积分10点,以后积分到一定时候可以领取奖品,需要增加一个积分算法,构造方法有两个参数:条件和返点,让它继承CashSuper,再到收费对象生成工厂增加满100积分10点的分支条件。
这样看起来好像还是有点麻烦,简单工厂模式虽然可以解决这个问题,但这个模式只是解决对象创建问题,而且由于工厂本身包括了所有的收费方式,商场是可能经常更换促销方式,每次维护或者扩展收费方式都要改动这个工厂,以致代码需要重新编译部署。
面对算法经常变动,有更好的办法,那就是策略模式。
四、策略模式 代码3.0
策略模式结构图:
本例 中的结构图:
CashNormal、CashRebate、CashReturn和CashSuper不动,CashFactory暂时不用,新增一个CashContext,然后修改客户端程序。
4.1. 代码
CashContext 类:
public class CashContext {
private CashSuper cs;
public CashContext(CashSuper cs) {
this.cs = cs;
}
public double getResult(double money){
return cs.acceptCash(money);
}
}
客户程序主要部分:
public class StrategyMode {
public static void main(String[] args) {
CashContext cashContext = null;
String type = "打八折";
switch (type){
case "正常收费":
cashContext = new CashContext(new CashNormal());
break;
case "打八折":
cashContext = new CashContext(new CashRebate(0.8));
break;
case "满300返100":
cashContext = new CashContext(new CashReturn(300,100));
break;
}
double result = cashContext.getResult(300);
System.out.println("最后的金额为:"+result);//240.0
}
}
4.2. 存在的问题
策略模式使用上了,但是这个程序还是需要在客户端去判断使用哪一算法,还需要进行改进。
那么如何将这个判断过程从客户端程序移走呢?可以使用工厂模式。
简单工厂模式不一定是一个单独的类,可以和策略模式的Context结合。
五、 代码3.1 策略模式与简单工厂模式联合
5.1. 代码
改造后的CashContext 类:
public class CashContext {
private CashSuper cs;
//构造函数的参数不是具体的收费策略对象,而是类型
public CashContext(String type) {
switch (type){
case "正常收费":
cs = new CashNormal();
break;
case "打八折":
cs = new CashRebate(0.8);
break;
case "满300返100":
cs = new CashReturn(300,100);
break;
}
}
public double getResult(double money){
return cs.acceptCash(money);
}
}
客户程序主要部分:
public class StrategyMode {
public static void main(String[] args) {
CashContext cashContext = null;
String type = "打八折";
cashContext = new CashContext(type);
double result = cashContext.getResult(200);
System.out.println("最后的金额为:"+result);
}
}
5.2. 这样做的好处
总结
面向对象编程并不是类越多越好,类得划分是为了封装,但分类得基础是抽象,具有相同属性和功能得对象得抽象集合才是类。
在开始编程时,我们