个人风格系列笔记,将《大话设计模式》中c#代码做java实现,稍有修改,逻辑不会太详细,不喜勿喷,适用于复习设计模式而做此分享。
商场收银软件,营业员根据客户所购买的商品单价和数量,向客户收费。
/** * 普通实现 * created by callmedevil on 2019/6/1. */ public class normaltest { public static void main(string[] args) { double price = 10; double num = 5; system.out.println(string.format("单价:%s 元", price)); system.out.println(string.format("数量:%s 个", num)); system.out.println(string.format("总价:%s 元", calculatetotal(price, num))); } /** * 计算总价 * * @param price 单价 * @param num 数量 * @return */ private static double calculatetotal(double price, double num) { return price * num; } }
商品搞促销,打八折,也可能打七折,甚至五折。
/** * 普通实现2 * created by callmedevil on 2019/6/1. */ public class normaltest2 { public static void main(string[] args) { double price = 10; double num = 5; string[] discounts = {"正常收费", "打八折", "打七折", "打五折"}; system.out.println(string.format("单价:%s 元", price)); system.out.println(string.format("数量:%s 个", num)); system.out.println(string.format("折扣:%s ", discounts[1])); system.out.println(string.format("总价:%s 元", calculatetotal(price, num, 1))); } /** * 计算总价 * * @param price 单价 * @param num 数量 * @param discount 折扣 * @return */ private static double calculatetotal(double price, double num, int discount) { double total = 0l; switch (discount) { case 0: total = price * num; break; case 1: total = price * num * 0.8; break; case 2: total = price * num * 0.7; break; case 3: total = price * num * 0.5; break; default: break; } return total; } }
有很多重复代码,就switch语句来说,如果计算方式比较复杂,那么这里就会显得非常冗余,必须考虑重构,抽出共性代码。而且如果需要打其他折扣,修改的地方也很多。
面向对象的编程,并不是类越多越好,类的划分是为了封装,但分类的基础是抽象,具有相同属性和功能的对象的抽象集合才是类。
/** * 现金收费抽象类 * created by callmedevil on 2019/6/1. */ public abstract class cashsuper { /** * 收取现金 * * @param money 原价 * @return 当前价 */ public abstract double acceptcash(double money); }
/** * 正常收费子类 * created by callmedevil on 2019/6/1. */ public class cashnormal extends cashsuper { @override public double acceptcash(double money) { // 正常收费,原价返回 return money; } }
/** * 返利收费子类 * created by callmedevil on 2019/6/1. */ public class cashreturn extends cashsuper{ // 返利条件 private double moneycondition = 0; // 返利值 private double moneyreturn = 0; // 返利收费,初始化时必须输入返利条件和返利值,比如满300返100, // 则moneycondition 为300,moneyreturn 为100 public cashreturn(double moneycondition, double moneyreturn) { this.moneycondition = moneycondition; this.moneyreturn = moneyreturn; } @override public double acceptcash(double money) { double result = money; if (money >= moneycondition) { // 若大于返利条件,则需要减去返利值 result = money - math.floor(money / moneycondition) * moneyreturn; } return result; } }
/** * 打折收费子类 * created by callmedevil on 2019/6/1. */ public class cashrebate extends cashsuper{ // 折扣率 private double moneyrebate = 1; public cashrebate(double moneyrebate) { // 打折收费,初始化时,必须输入折扣率,如打八折,就是0.8 this.moneyrebate = moneyrebate; } @override public double acceptcash(double money) { return money * moneyrebate; } }
/** * 现金收费工厂类 * created by callmedevil on 2019/6/1. */ public class cashfactory { /** * 创建现金收取工厂实例 * * @param type 收费类型 * @return */ public static cashsuper createcashaccept(string type) { cashsuper cs = null; switch (type) { case "正常收费": cs = new cashnormal(); break; case "满300减100": cs = new cashreturn(300, 100); break; case "打8折": cs = new cashrebate(0.8); break; default: break; } return cs; } }
/** * 现金收费测试 * created by callmedevil on 2019/6/1. */ public class cashtest { public static void main(string[] args) { double price = 400; double num = 3; system.out.println(string.format("单价:%s 元,数量:%s 个", price, num)); string type = "正常收费"; cashsuper cashsuper = cashfactory.createcashaccept(type); double total = cashsuper.acceptcash(price) * num; system.out.println(string.format("折扣:%s;总价:%s 元", type, total)); type = "满300减100"; cashsuper = cashfactory.createcashaccept(type); total = cashsuper.acceptcash(price) * num; system.out.println(string.format("折扣:%s;总价:%s 元", type, total)); type = "打8折"; cashsuper = cashfactory.createcashaccept(type); total = cashsuper.acceptcash(price) * num; system.out.println(string.format("折扣:%s;总价:%s 元", type, total)); } }
输出结果
单价:400.0 元,数量:3.0 个 折扣:正常收费;总价:1200.0 元 折扣:满300减100;总价:900.0 元 折扣:打8折;总价:960.0 元
简单工厂模式虽然也能够解决问题2,但这个模式只是解决对象的创建问题,而且由于工厂本身包括了所有的收费模式,商场是可能经常性的更改打折额度和返利额度,每次维护或扩展收费方式都要改动这个工厂,以致代码需要重新编译部署,这是很糟糕的,所以不是最好的解决办法。
定义了算法家族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化,不回影响到使用算法的客户。
其实上面的简单工厂模式实现方式里面的cashsuper、cashnormal、cashrebate、cashreturn都不需要更改,只需要增加一个cashcontext类,同时修改下客户端就可以了。
/** * 现金上下文 * created by callmedevil on 2019/6/1. */ public class cashcontext { private cashsuper cs = null; public cashcontext(string type) { switch (type) { case "正常收费": cs = new cashnormal(); break; case "满300减100": cs = new cashreturn(300, 100); break; case "打8折": cs = new cashrebate(0.8); break; default: break; } } public double getresult(double money) { return cs.acceptcash(money); } }
/** * 策略模式测试 * created by callmedevil on 2019/6/1. */ public class contexttest { public static void main(string[] args) { double price = 400; double num = 3; system.out.println(string.format("单价:%s 元,数量:%s 个", price, num)); string type = "正常收费"; cashcontext cashcontext = new cashcontext(type); double total = cashcontext.getresult(price) * num; system.out.println(string.format("折扣:%s;总价:%s 元", type, total)); type = "满300减100"; cashcontext = new cashcontext(type); total = cashcontext.getresult(price) * num; system.out.println(string.format("折扣:%s;总价:%s 元", type, total)); type = "打8折"; cashcontext = new cashcontext(type); total = cashcontext.getresult(price) * num; system.out.println(string.format("折扣:%s;总价:%s 元", type, total)); } }
策略模式测试类中的代码与简单工厂的非常相似,因为这里将策略模式与简单工厂模式做了结合,因此比较难以判断策略模式的好处到底在哪。如果仔细分析一下会发现,只用简单工厂的测试类中,也就是客户端代码耦合了cashsuper和cashfactory两个类,而使用了策略模式的客户端只涉及到了cashcontext一个类,将客户端与具体算法的实现进行了解耦,这样如果商场需要变更促销折扣时,除了变更具体的折扣实现类,只需要更改cashcontext即可,客户端完全不用做任何更改,这就是策略模式带来的最大好处。
如对本文有疑问, 点击进行留言回复!!
网友评论