策略模式:
它定义了算法家族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化。不会影响到使用算法的客户
以商店打折为例子:
商店没有做活动,那么收费就是正常收费
商店如果进行活动,那么就会有优惠方式;比如是打折,或者是满300返100等等
这些都是算法,算法本省就是一种策略,他的特点就是完成的工作相同,只是实现不同;所以策略模式就是讲这些算法封装起来
1.策略模式
UML图形:
namespace 策略模式
{
//抽象类---收费方式类(不同收费方式对应的价格的抽象)
public abstract class CashSuper
{
//抽象方法
public abstract double acceptCash(double money);
}
}
namespace 策略模式
{
//价格正常类(子类)(对价格正常的抽象,继承于收费方式---正常收费方式)
class CashNormal:CashSuper
{
//对抽象方法acceptCash方法重写
public override double acceptCash(double money)
{
return money;
}
}
}
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;
}
}
}
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;
}
}
}
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);
}
}
}
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 = "";
}
}
}
2.策略模式+简单工厂
策略模式需要在客户端判断用哪个算法,那么为了解决这个问题就可以将策略模式和简单工厂结合起来。具体的方法就是简单工厂与策略模式中的Context类结合
改进的Cashtext代码:
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);
}
}
}
客户端代码(主要部分):
#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
3.策略模式+简单工厂+反射
为了避免每次添加新的打折方法都要修改switch语句,我们利用反射将switch语句替换掉
改进的Cashtext代码:
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);
}
}
}
客户端代码(主要部分):
#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();
}
//转换字符串函数
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