设计模式记录3之“策略者模式”
今天学习了《大话设计模式》中的策略者模式。
定义:策略模式就是用来封装算法的。在实践中,我们用它来封装几乎任何类型的规则,只要在分析过程中听到任何时间有任何不同的应用规则,就可以考虑使用策略者模式处理这种变化的可能性。
优点:1 定义了一系列可重用的算法和行为,其中用到的继承有助于取出这些算法中的公共功能;
2 简化了单元测试,每个类都是一个单独的算法,可以外接一个自己的接口进行测试。
场景: 一个商场的收银系统,有时候是"正常收费",有时候"打八折",有"满300减20"......各种收银的可能性都有。于是在这里我们就可以用到"策略模式"。
思路:定义一个接口,定义所有的算法的接口。创建各种算法(正常收费,打八折.....都是算法) ,继承算法接口,实现具体的算法方法。创建策略模式类,根据条件指定实现哪一个算法的实例。创建客户端,只需要传入参数即可。上代码:
Step 1:
/// 策略者模式
/// 定义算法接口
/// </summary>
interface InterfaceStrategy
{
void GetStrategy();
}
step 2:
/// 算法A类继承接口
/// </summary>
class StrategyA:InterfaceStrategy
{
public void GetStrategy()
{
Console.WriteLine("继承了A类算法");
}
}
/// <summary>
/// 算法B类,继承接口
/// </summary>
class StrategyB:InterfaceStrategy
{
public void GetStrategy()
{
Console.WriteLine("实现了B类算法");
}
}
step 3:
{
InterfaceStrategy strategy = null;//算法接口,定义在外层
/// <summary>
/// 策略这模式与简单工厂模式相结合
/// 根据调试决定实例化哪个算法
/// </summary>
public StrategyContext(string type)
{
switch (type)
{
case "A":
StrategyA a = new StrategyA();
strategy = a;
break;
case "B":
StrategyB b = new StrategyB();
strategy = b;
break;
default:
break;
}
}
//执行这个方法的时候,strategy对象已经通过switch分支语句获得了具体的行为对象
public void GetStrategyResult()
{
strategy.GetStrategy();
}
}
step 4:
/// 策略者模式
/// 客户端
/// </summary>
/// <param name="args"></param>
static void Main(string[] args)
{
string type="A";
//将算法参数传入StrategyContext中,构造函数实例化
StrategyContext context = new StrategyContext(type);
context.GetStrategyResult();
Console.ReadLine();
}
输出结果根据传入的参数"type"决定实例化哪个算法的实例。
到这里,我也跟书中小菜一样,觉得跟简单工厂一样,都是在switch语句中实现的,简单工厂是根据条件判断实例化那一个对象,策略者模式是根据条件判断实现哪一个算法。总觉得两者差不多。思考中?
---------
题外话:反射
MSDN介绍:
反射提供了封装程序集,模块和类型的对象(Type类型)。可以使用反射动态创建类型的实例,将类型绑定到现有对象,或从现有的对象获取类型并调用其方法或者访问其字段和属性。如果代码中使用了属性,可以利用反射对它们进行访问。
用静态方法GetType 从 Object基类派生的所有类型都继承该方法,获取变量类型的简单反射示例:
System.Type type = i.GetType();
System.Console.WriteLine(type);
输入为:
System.Int32
使用反射获取已加载的程序集的完整名称:
System.Console.WriteLine(o.GetName());
输出为:
mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
反射在策略模式中的应用:
对于以上的代码,需要改的有两个地方,一个地方是Step3,去掉繁琐的switch语句,用一个方法代替,上代码:
/// 利用反射机制
/// </summary>
private InterfaceStrategy infaceStrategy;
public void setBehavior(InterfaceStrategy super)
{
this.infaceStrategy = super;
super.GetStrategy();
}
另一个也是反射应用的关键,step 4,客户端应用:
StrategyContext context = new StrategyContext();
context.setBehavior((InterfaceStrategy)Assembly.Load("Strategy").CreateInstance("Strategy.StrategyB"));
Console.ReadLine();
这样的话输出结果是"实现了B类算法"。其中反射的重点是:
此处客户端我是为了简单才这样写的,其中 CreateInstance("Strategy.StrategyB")的参数"命名空间.类名称"中的类名称,存储在XML文件中,然后在客户端中读取出来,这样当我们要用用哪个算法的时候就只需要更改XML就可以了。
XML文件如下:
<CashAcceptType>
<type>
<name>A</name>
<class>StrategyA</class>
</type>
<type>
<name>B</name>
<class>StrategyB</class>
</type>
</CashAcceptType>