State模式与Strategy模式
在前面的随笔中我提到了用State模式来处理绩效包的分等,后来在idior的回复中看到了关于使用State模式还是Strategy的取舍,随即温习了一下State模式(实际上是学习,用温习是假装看过)。所以将她俩之间的区别阐述如下:
在我们设计的时候应该考虑“不变性”与“可变性”,如果说一个环境中状态可能一直有变化,比如在计算包的分等的时候可能不断切换分等算法,这样就应该使用State模式。而如果我们的需求是算法一旦确定不会改变,这也正是策略模式所处理的,因为策略模式环境一旦创建,那么在环境的整个生命周期内都不会改变具体策略类。
在实现上,State模式在Context类中添加了State属性,也就是说在环境被创建后还可以切换各个State类,代码如下。

/**//*******************************************************
* 状态模式
* 状态模式与策略模式比较容易混淆,实际上她俩的区别主要
* 在环境的可变性上,如果环境有明显的状态转换,那么就应该
* 采用状态模式,否则选择策略模式。从这个例子中也可以看出
* 她的实现和策略模式的实现的区别仅在状态类Context。
* *****************************************************/
using System;
namespace StatePattern


{

/**//// <summary>
/// Class1 的摘要说明。
/// </summary>
class StatePattern

{

/**//// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread]
static void Main(string[] args)

{
Context o_Context=new Context(new RateClassifyCalculater());
o_Context.ContextIterface();
//这里实现的状态的迁移,进而改变对象的行为。
o_Context.State=new RangeClassifyCalculater();
o_Context.ContextIterface();
Console.ReadLine();
}
}

状态模式的抽象类#region 状态模式的抽象类
abstract public class State

{

/**//// <summary>
/// 包分等计算的主逻辑框架
/// </summary>
public void MainCalculateLogic()

{
Console.WriteLine("Template Method Called");
ProjectCalculater();
PackageCalculater();
ClassifyPackage();
}

/**//// <summary>
/// 计算包中方案总得分的抽象方法
/// </summary>
abstract public void ProjectCalculater();

/**//// <summary>
/// 计算最终包的得分的抽象方法
/// </summary>
abstract public void PackageCalculater();

/**//// <summary>
/// 将计算好的包进行分等的抽象方法
/// </summary>
abstract public void ClassifyPackage();
}
#endregion

状态模式的实现类#region 状态模式的实现类
class RateClassifyCalculater:State

{

/**//// <summary>
/// 比例分等计算的方案计算具体实现
/// </summary>
public override void ProjectCalculater()

{
Console.WriteLine("Rate classify's calculater of project score called");
}

/**//// <summary>
/// 比例分等计算的包分数计算具体实现
/// </summary>
public override void PackageCalculater()

{
Console.WriteLine("Rate classify's calculater of package score called");
}

/**//// <summary>
/// 比例分等计算的包分等策略具体实现
/// </summary>
public override void ClassifyPackage()

{
Console.WriteLine("Rate classify's calculater of package classify logic called");
}
}
class RangeClassifyCalculater:State

{

/**//// <summary>
/// 分数区间分等计算的方案计算具体实现
/// </summary>
public override void ProjectCalculater()

{
Console.WriteLine("Range classify's calculater of project score called");
}

/**//// <summary>
/// 分数区间分等计算的包分数计算具体实现
/// </summary>
public override void PackageCalculater()

{
Console.WriteLine("Range classify's calculater of package score called");
}

/**//// <summary>
/// 分数区间分等计算的包分等策略具体实现
/// </summary>
public override void ClassifyPackage()

{
Console.WriteLine("Range classify's calculater of package classify logic called");
}
}
#endregion

状态模式的环境类,与策略模式的区别在与该类#region 状态模式的环境类,与策略模式的区别在与该类

/**//// <summary>
/// 状态模式的环境类,用与控制状态间的转换
/// </summary>
public class Context

{
private State state;

/**//// <summary>
/// 环境的初始化
/// </summary>
/// <param name="initState">初始化状态</param>
public Context(State initState)

{
this.state=initState;
}

/**//// <summary>
/// 环境类所维护的状态属性
/// </summary>
public State State

{
get

{
return this.state;
}
set

{
this.state=value;
}
}

/**//// <summary>
/// 环境接口
/// </summary>
public void ContextIterface()

{
Console.WriteLine("State Context Interface called");
this.state.MainCalculateLogic();
}
}
#endregion
}
执行结果如下:
另外环境类也可以作为参数传送给状态类,如果状态类需要就可以调节环境对象。这其实涉及到一个谁来改变状态的权衡,由环境来处理比较保险,由状态类自身决定状态的转换则更加灵活,但这种改变个人感觉好象有点失控,因为你可能在不知道的情况下环境类的状态就被改变了,所以最好在 状态子类传入Context对象的时候显式的用ref关键字,这样就可以意识到可能Context对象要改变,如果不用ref关键字,虽然效果可能一样,但是起到的警示作用是不同的。
所以在使用State和Strategy模式的时候,首要考虑的是环境状态是否是可变的。
在我们设计的时候应该考虑“不变性”与“可变性”,如果说一个环境中状态可能一直有变化,比如在计算包的分等的时候可能不断切换分等算法,这样就应该使用State模式。而如果我们的需求是算法一旦确定不会改变,这也正是策略模式所处理的,因为策略模式环境一旦创建,那么在环境的整个生命周期内都不会改变具体策略类。
在实现上,State模式在Context类中添加了State属性,也就是说在环境被创建后还可以切换各个State类,代码如下。
执行结果如下:
另外环境类也可以作为参数传送给状态类,如果状态类需要就可以调节环境对象。这其实涉及到一个谁来改变状态的权衡,由环境来处理比较保险,由状态类自身决定状态的转换则更加灵活,但这种改变个人感觉好象有点失控,因为你可能在不知道的情况下环境类的状态就被改变了,所以最好在 状态子类传入Context对象的时候显式的用ref关键字,这样就可以意识到可能Context对象要改变,如果不用ref关键字,虽然效果可能一样,但是起到的警示作用是不同的。
所以在使用State和Strategy模式的时候,首要考虑的是环境状态是否是可变的。
