设计模式|由浅入深大话设计模式——策略模式

这次我们依旧是从一个简单的小问题开始~鉴于本人不会C#的可视化编程QAQ,,所以以后涉及UI的一律用unity处理,不过UI不是主要部分,我做的也比较简陋,不要在意哈,大家用什么都好~~~

那么这次的问题就是:做一个商场收银软件,营业员要根据客户所购买的商品单价和数量,向客户收费。
那么我们先考虑最简单的方法,只需要一个单价和数量的输入文本框,一个记录总费用的字段,然后计算每个商品的费用显示出来就好了就好了,就像下面这样
设计模式|由浅入深大话设计模式——策略模式
文章图片

public class 策略例子 : MonoBehaviour { public InputField prices; public InputField nums; public Text showTex; public Button okBtn; private float total = 0.0f; // Start is called before the first frame update void Start() { okBtn.onClick.AddListener(OnClickOkBtn); }public void OnClickOkBtn() { var price = int.Parse(prices.text); var num = int.Parse(nums.text); total += (price * num); showTex.text = total.ToString(); } }

这样是可以了,但是如果商场要搞活动打折呢?
那我们加个打折下拉框吧
设计模式|由浅入深大话设计模式——策略模式
文章图片

public class 策略例子 : MonoBehaviour { public InputField prices; public InputField nums; public Text showTex; public Button okBtn; public Dropdown dropdown; private float total = 0.0f; private float discount = 1.0f; // Start is called before the first frame update void Start() { okBtn.onClick.AddListener(OnClickOkBtn); } public void OnClickOkBtn() { var price = int.Parse(prices.text); var num = int.Parse(nums.text); OnDropDownChange(dropdown.options[dropdown.value].text); total += (price * num)* discount; showTex.text = "当前价格:"+total.ToString(); } public void OnDropDownChange(string arg) { switch (arg) { case "八折": discount = 0.8f; break; case "五折": discount = 0.5f; break; case "三折": discount = 0.3f; break; default: break; } } }

但是商场老板就喜欢玩新花样,现在又想加个满300反100的促销活动,现在是不是感觉就有点复杂了呢
但是想想这么多东西打折基本都是一样的,只不过打折方式不一样,我们能不能用简单工厂处理呢?(打一折和打九折只是形式不同,抽象分析出来,同时所有的打折算法都是一样的,所以应该每一种打折算法是一个类。)
面向对象编程,并不是类越多越好,类的划分是为了封装,但分类的基础是抽象,具有相同属性和功能的对象的抽象集合才是类。
public class 策略例子 : MonoBehaviour { public InputField prices; public InputField nums; public Text showTex; public Button okBtn; public Dropdown dropdown; private float total = 0.0f; private float discount = 1.0f; // Start is called before the first frame update void Start() { okBtn.onClick.AddListener(OnClickOkBtn); } public void OnClickOkBtn() { var price = int.Parse(prices.text); var num = int.Parse(nums.text); var csuper = CashFactory.createCashAccept(dropdown.options[dropdown.value].text); total = num * price; total = csuper.acceptCash(total); showTex.text = "当前价格:"+total.ToString(); } } //收费父类 abstract class CashSuper { //现金收取父类,收取现金,参数为原价,返回打折后的价 public abstract float acceptCash(float money); } class CashNromal: CashSuper { public override float acceptCash(float money) { return money; } } class CashRebate : CashSuper { private float moneyRebate = 1f; public CashRebate(float moneyRebate) { this.moneyRebate = moneyRebate; } public override float acceptCash(float money) { return moneyRebate * money; } } class CashReturn: CashSuper { private float moneyCondition = 0.0f; private float moneyReturn = 0.0f; public CashReturn(float moneyCondition,float moneyReturn) { this.moneyCondition = moneyCondition; this.moneyReturn = moneyReturn; } public override float acceptCash(float money) { float result = money; if (money >= moneyCondition) { result = money - Mathf.Floor((float)money / moneyCondition) * moneyReturn; } return result; } //收费工厂类 public class CashFactory { public static CashSuper createCashAccept(string type) { CashSuper cs = null; switch (type) { case "正常收费": cs = new CashNromal(); break; case "满300反100": cs = new CashReturn(300,100); break; case "打八折": cs = new CashRebate(0.8f); break; default: break; } return cs; } } }

这样代码看上去是不是好多了呢,如果在加别的活动的话只需要增加相应的子类和UI下拉框内容即可。但是工厂本身包括了所有的收费方式,商场可能会经常性的更改打折模式,每次维护或扩展收费方式都需要去改动这个工厂,这并不是一个最好的办法。面对算法的时长变动,我们应该用一个更好地设计模式处理。
策略模式
策略模式定义了算法家族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化,不会影响到使用算法的客户。
让我们先看一下策略算法的基本结构
设计模式|由浅入深大话设计模式——策略模式
文章图片

public class 策略模式 : MonoBehaviour { Context context; private void Start() { context = new Context(new ConcreteStrategyA()); context.ContextInterface(); context = new Context(new ConcreteStrategyB()); context.ContextInterface(); } } abstract class Strategy { //算法方法 public abstract void AlgorithmInterfacs(); } //具体算法 class ConcreteStrategyA: Strategy { public override void AlgorithmInterfacs() { Debug.Log("算法A实现"); } } class ConcreteStrategyB : Strategy { public override void AlgorithmInterfacs() { Debug.Log("算法B实现"); } } class Context { Strategy strategy; public Context(Strategy strategy) { this.strategy = strategy; } //上下接口 public void ContextInterface() { strategy.AlgorithmInterfacs(); } }

那我们把刚才的例子改一下吧(这个其实是策略模式与简单工厂结合使用)
public class 策略例子 : MonoBehaviour { public InputField prices; public InputField nums; public Text showTex; public Button okBtn; public Dropdown dropdown; private float total = 0.0f; private float discount = 1.0f; // Start is called before the first frame update void Start() { okBtn.onClick.AddListener(OnClickOkBtn); } public void OnClickOkBtn() { var price = int.Parse(prices.text); var num = int.Parse(nums.text); CashContext cc = new CashContext(dropdown.options[dropdown.value].text); total = num * price; total = cc.GetResult(total); showTex.text = "当前价格:" + total.ToString(); } } abstract class CashSuper { //现金收取父类,收取现金,参数为原价,返回打折后的价 public abstract float acceptCash(float money); } class CashNromal : CashSuper { public override float acceptCash(float money) { return money; } } class CashRebate : CashSuper { private float moneyRebate = 1f; public CashRebate(float moneyRebate) { this.moneyRebate = moneyRebate; } public override float acceptCash(float money) { return moneyRebate * money; } } class CashReturn : CashSuper { private float moneyCondition = 0.0f; private float moneyReturn = 0.0f; public CashReturn(float moneyCondition, float moneyReturn) { this.moneyCondition = moneyCondition; this.moneyReturn = moneyReturn; } public override float acceptCash(float money) { float result = money; if (money >= moneyCondition) { result = money - Mathf.Floor((float)money / moneyCondition) * moneyReturn; } return result; } //Context public class CashContext { private CashSuper cs; public CashContext(string type) { switch (type) { case "正常收费": cs =new CashNromal(); break; case "满300反100": cs = new CashReturn(300, 100); break; case "打八折": cs = new CashRebate(0.8f); break; default: break; } } public float GetResult(float money) { return cs.acceptCash(money); } } }

是不是觉得跟简单工厂模式挺像的~~让我们看一看他们有什么区别(感觉基本一样啊= =)
简单工厂模式客户端认识两个类,CashSuper和CashFactor
策略模式只需要认识一个类CashContext即可
【设计模式|由浅入深大话设计模式——策略模式】总结
策略模式是一种定义一系列算法的方法,从概念上来看,所有这些算法完成的都是相同的工作,只是实现不同。它可以以相同的方式调用所有的算法,减少了各种算法类与使用算法类之间的耦合。
优点:
1.Strategy类层次为Context定义了一系列的可供重用的算法或行为。继承有助于析取出这些算法中的公共功能。
2.策略模式的优点是简化了单位测试,因为每个算法都有自己的类,可以通过自己的接口单独测试。
用法:
策略模式就是用来封装算法的,但在实践中,我们可以发现用它来封装几乎任何类型的规则,只要在分析过程中听到需要在不同时间应用不同的业务规则,就可以考虑用策略模式处理这种变化的可能性。

    推荐阅读