今天学习了《大话设计模式》中的策略者模式。
定义:策略模式就是用来封装算法的。在实践中,我们用它来封装几乎任何类型的规则,只要在分析过程中听到任何时间有任何不同的应用规则,就可以考虑使用策略者模式处理这种变化的可能性。
优点:1 定义了一系列可重用的算法和行为,其中用到的继承有助于取出这些算法中的公共功能;
2 简化了单元测试,每个类都是一个单独的算法,可以外接一个自己的接口进行测试。
场景: 一个商场的收银系统,有时候是"正常收费",有时候"打八折",有"满300减20"......各种收银的可能性都有。于是在这里我们就可以用到"策略模式"。
思路:定义一个接口,定义所有的算法的接口。创建各种算法(正常收费,打八折.....都是算法) ,继承算法接口,实现具体的算法方法。创建策略模式类,根据条件指定实现哪一个算法的实例。创建客户端,只需要传入参数即可。上代码:
Step 1:
///
<summary>
///
策略者模式
///
定义算法接口
///
</summary>
interface
InterfaceStrategy
{
void
GetStrategy();
}
step 2:
///
<summary>
///
算法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:
class
StrategyContext
{
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>
///
策略者模式
///
客户端
///
</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基类派生的所有类型都继承该方法,获取变量类型的简单反射示例:
int
i
=
42
;
System.Type type
=
i.GetType();
System.Console.WriteLine(type);
输入为:
System.Int32
使用反射获取已加载的程序集的完整名称:
System.Reflection.Assembly o
=
System.Reflection.Assembly.Load(
"
mscorlib.dll
"
);
System.Console.WriteLine(o.GetName());
输出为:
mscorlib, Version
=
2.0
.
0.0
, Culture
=
neutral, PublicKeyToken
=
b77a5c561934e089
反射在策略模式中的应用:
对于以上的代码,需要改的有两个地方,一个地方是Step3,去掉繁琐的switch语句,用一个方法代替,上代码:
///
<summary>
///
利用反射机制
///
</summary>
private
InterfaceStrategy infaceStrategy;
public
void
setBehavior(InterfaceStrategy super)
{
this
.infaceStrategy
=
super;
super.GetStrategy();
}
另一个也是反射应用的关键,step 4,客户端应用:
//
利用反射机制实现
CreateInstance(
"
Strategy.StrategyB
"
)
中的参数动态的获取实例
StrategyContext context
=
new
StrategyContext();
context.setBehavior((InterfaceStrategy)Assembly.Load(
"
Strategy
"
).CreateInstance(
"
Strategy.StrategyB
"
));
Console.ReadLine();
这样的话输出结果是"实现了B类算法"。其中反射的重点是:
Assembly.Load("程序集名称").CreateInstance("命名空间.类名称")
此处客户端我是为了简单才这样写的,其中 CreateInstance("Strategy.StrategyB")的参数"命名空间.类名称"中的类名称,存储在XML文件中,然后在客户端中读取出来,这样当我们要用用哪个算法的时候就只需要更改XML就可以了。
XML文件如下:
<?
xml version="1.0" encoding="utf-8"
?>
<
CashAcceptType
>
<
type
>
<
name
>
A
</
name
>
<
class
>
StrategyA
</
class
>
</
type
>
<
type
>
<
name
>
B
</
name
>
<
class
>
StrategyB
</
class
>
</
type
>
</
CashAcceptType
>