策略模式:
它定义了算法家族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化。不会影响到使用算法的客户
以商店打折为例子:
商店没有做活动,那么收费就是正常收费
商店如果进行活动,那么就会有优惠方式;比如是打折,或者是满300返100等等
这些都是算法,算法本省就是一种策略,他的特点就是完成的工作相同,只是实现不同;所以策略模式就是讲这些算法封装起来
1.策略模式
UML图形:
代码实现:
- <span style="font-family:KaiTi_GB2312;font-size:18px;">namespace 策略模式
- {
- //抽象类---收费方式类(不同收费方式对应的价格的抽象)
- public abstract class CashSuper
- {
- //抽象方法
- public abstract double acceptCash(double money);
- }
- }
- </span>
- <span style="font-family:KaiTi_GB2312;font-size:18px;">namespace 策略模式
- {
- //价格正常类(子类)(对价格正常的抽象,继承于收费方式---正常收费方式)
- class CashNormal:CashSuper
- {
- //对抽象方法acceptCash方法重写
- public override double acceptCash(double money)
- {
- return money;
- }
- }
- }</span>
- <span style="font-family:KaiTi_GB2312;font-size:18px;">namespace 策略模式
- {
- //打折价格类(打折时候对应的不同价格子类---折扣收费方式)
- class CashRebate:CashSuper
- {
- private double moneyRebate = 1d;
- //创建一个构建函数---初始化时必须输入折扣率
- public CashRebate (string moneyRebate)
- {
- //将字符创转换为等效的double数字
- this.moneyRebate = double.Parse(moneyRebate);
- }
- //重写方法acceptCash
- public override double acceptCash(double money)
- {
- return money * moneyRebate;
- }
- }
- }
- </span>
- <span style="font-family:KaiTi_GB2312;font-size:18px;">using System;
- namespace 策略模式
- {
- //返利收费子类(达到返利条件会返值时的收费方式---返利收费方式)
- class CashReturn:CashSuper
- {
- //声明返利条件和返利值(私有--不可访问)
- private double moneyCondition = 0.0d;
- private double moneyReturn = 0.0d;
- //构造函数--初始化时必须输入返利条件和返利值
- public CashReturn(string moneyCondition, string moneyReturn)
- {
- this.moneyCondition = double.Parse(moneyCondition);
- this.moneyReturn = double.Parse(moneyReturn);
- }
- //重写acceptCash方法
- public override double acceptCash(double money)
- {
- double result = money;
- if (money >= moneyCondition)
- result = money - Math.Floor(money / moneyCondition) * moneyReturn;
- return result;
- }
- }
- }
- </span>
- <span style="font-family:KaiTi_GB2312;font-size:18px;">namespace 策略模式
- {
- //这个类完成的工作:根据参数type返回对应的价钱(type对应的子类赋给了cs)
- class CashContext
- {
- private CashSuper cs;
- //通过构造函数,传入具体的收费策略
- public CashContext(CashSuper csuper)
- {
- this.cs = csuper;
- }
- //根据收费策略的不同获得结果
- public double GetResult(double money)
- {
- return cs.acceptCash(money);
- }
- }
- }
- </span>
- <span style="font-family:KaiTi_GB2312;font-size:18px;">using System;
- using System.Windows.Forms;
- namespace 策略模式
- {
- public partial class Form1 : Form
- {
- public Form1()
- {
- InitializeComponent();
- }
- #region 策略模式
- double total = 0.0d;
- private void btnOK_Click(object sender, EventArgs e)
- {
- //用于总计
- double totalPrices = 0.0d;
- CashContext cc = null;
- //根据下拉选择框,将相应的策略对象作为参数,传入CashContext的对象中
- switch (comType.SelectedIndex.ToString())
- {
- case "正常收费":
- cc=new CashContext (new CashNormal ());
- break ;
- case "打八折":
- cc = new CashContext(new CashRebate("0.8"));
- break;
- case "满300返100":
- cc=new CashContext (new CashReturn ("300","100"));
- break;
- }
- //调用csuper的方法实现具体的收费计算
- totalPrices = cc.GetResult(Convert.ToDouble(txtPrice.Text)) * Convert.ToDouble(txtAmount.Text);
- //显示
- total=total+totalPrices ;
- listRuselt.Items.Add("单价:" + txtPrice.Text + " 数量:" + txtAmount.Text + " 收费方式:" + comType.SelectedItem + " 总价:" + totalPrices);
- labTotal.Text = total.ToString();
- }
- #endregion
- private void Form1_Load(object sender, EventArgs e)
- {
- //传入一个object类型的数组作为参数
- comType.Items.AddRange(new object[] { "正常收费", "打八折", "满300返100" });
- }
- private void btnRebuilt_Click(object sender, EventArgs e)
- {
- txtAmount.Text = "";
- txtPrice.Text = "";
- }
- }
- }</span>
2.策略模式+简单工厂
策略模式需要在客户端判断用哪个算法,那么为了解决这个问题就可以将策略模式和简单工厂结合起来。具体的方法就是简单工厂与策略模式中的Context类结合
改进的Cashtext代码:
- <span style="font-family:KaiTi_GB2312;font-size:18px;">namespace 策略模式
- {
- //这个类完成的工作:根据参数type返回对应的价钱(type对应的子类赋给了cs)
- class CashContext
- {
- //实例化父类cs对象----调用公共的功能计算结果
- CashSuper csuper = null;
- //和工厂类相比,这个没有返回值
- //参数不是具体的收费策略对象,而是一个字符串,表示收费类型
- public CashContext(string type)
- {
- switch (type)
- {
- case "正常收费":
- CashNormal cr0 = new CashNormal();
- csuper = cr0;
- break;
- case "打八折":
- CashRebate cr1 = new CashRebate("0.8");
- csuper = cr1;
- break;
- case "满300减100":
- CashReturn cr2 = new CashReturn("300", "100");
- csuper = cr2;
- break;
- }
- }
- public double GetResult(double money)
- {
- //csuper直接调用静态方法 返回对应的值
- return csuper.acceptCash(money);
- }
- }
- }</span>
客户端代码(主要部分):
- <span style="font-family:KaiTi_GB2312;font-size:18px;">#region 策略模式+简单工厂
- double total = 0.0d;
- private void btnOK_Click(object sender, EventArgs e)
- {
- //用于总计
- double totalPrices = 0.0d;
- //根据下拉选择框,将相应的算法类型字符串传入CashContext的对象中
- CashContext csuper = new CashContext(comType.SelectedIndex.ToString());
- //调用csuper的方法实现具体的收费计算
- totalPrices = csuper.GetResult(Convert.ToDouble(txtPrice.Text)) * Convert.ToDouble(txtAmount.Text);
- //显示
- total=total+totalPrices ;
- listRuselt.Items.Add("单价:" + txtPrice.Text + " 数量:" + txtAmount.Text + " 收费方式:" + comType.SelectedItem + " 总价:" + totalPrices);
- labTotal.Text = total.ToString();
- }
- #endregion</span>
3.策略模式+简单工厂+反射
为了避免每次添加新的打折方法都要修改switch语句,我们利用反射将switch语句替换掉
改进的Cashtext代码:
- <span style="font-family:KaiTi_GB2312;font-size:18px;">using System.Reflection;
- namespace 策略模式
- {
- class CashContext
- {
- CashSuper csuper;
- private string Type;
- public CashContext(string Type)
- {
- //应用反射将原来的switch语句去掉
- this.Type = Type;
- csuper = (CashSuper)Assembly.Load("策略模式").CreateInstance("策略模式."+this.Type);
- }
- public double GetResult(double money)
- {
- //csuper直接调用静态方法 返回对应的值
- return csuper.acceptCash(money);
- }
- }
- }</span>
客户端代码(主要部分):
- <span style="font-family:KaiTi_GB2312;font-size:18px;"> #region 策略模式
- double total = 0.0d;
- private void btnOK_Click(object sender, EventArgs e)
- {
- //用于总计
- double totalPrices = 0.0d;
- CashContext csuper = new CashContext(strName(comType.SelectedIndex));
- //调用csuper的方法实现具体的收费计算
- totalPrices = csuper.GetResult(Convert.ToDouble(txtPrice.Text)) * Convert.ToDouble(txtAmount.Text);
- //显示
- total=total+totalPrices ;
- listRuselt.Items.Add("单价:" + txtPrice.Text + " 数量:" + txtAmount.Text + " 收费方式:" + comType.SelectedItem + " 总价:" + totalPrices);
- labTotal.Text = total.ToString();
- }</span>
- <span style="font-family:KaiTi_GB2312;font-size:18px;"> //转换字符串函数
- string strType;
- public string strName(int type)
- {
- switch (type)
- {
- case 0:
- strType = "CashNormal";
- break;
- case 1:
- strType = "CashRebate";
- break;
- case 2:
- strType = "CashReturn";
- break;
- }
- return strType;
- }
- #endregion</span>