状态模式
定义
当一个对象的内在状态改变时同意改变其行为,这个对象看起来像是改变了其类。
状态模式的核心是封装。状态的变更引起了行为的变更,从外部看起来就好像这个对象相应的类发生了改变一样。
通用类图例如以下:
1.State——抽象状态角色
接口或者抽象类。负责对象状态定义。而且封装角色以实现状态切换
2.ConcreteState——详细状态角色
每个详细状态必须完毕两个职责:本状态行为管理以及怎样过渡到其它状态
3.Context——环境角色
定义client的接口,而且负责详细状态的切换
通用代码
class Context { private State state; public Context(State state) { this.state = state; } public State State { get { return state; } set { state = value; Console.WriteLine("当前状态:" + state.GetType().Name); } } public void Request() { state.Handle(this); } } abstract class State { public abstract void Handle(Context context); } class ConcreteStateA : State { public override void Handle(Context context) { context.State = new ConcreteStateB(); } } class ConcreteStateB : State { public override void Handle(Context context) { context.State = new ConcreteStateA(); } }
在上述过程中,我们隐藏了状态的变化过程。它的切换引起了行为的变化。
对外来说,我们仅仅看到行为的发生改变。而不用知道是状态变化引起的。
使用场景
1.行为随状态改变而改变的场景
2.条件、分支推断语句的替代者
牛刀小试
基于此,就结合机房收费学生下机时的计算金额来做一个小样例。
我们知道在学生下机时。须要依据学生所花费的时间来进行计算。假设小于准备时间的话。则不计费;假设在至少上机时间内的话。则按最少金额来算,否则则正常计算。我们看到这会涉及到大量的条件分支语句。正好负责状态模式的场景应用。
在此把时间段划分为四个状态。
ForenoonState:代表在准备时间段内
NoonState:代表在至少上机时间段内
AfternoonState:代表超过至少上机段
注意:为了方便。就以这三个名称表示这三个时间段
类图例如以下
代码例如以下
Public Class Work '定义眼下的状态变量 Private current As State '学生所花费的金额变量 Private money As Single '构造函数用来初始化状态 Public Sub New() current = New ForenoonState End Sub '消费的时间 Private consumeTime As Single Property GetConsumeTime As Single Get Return consumeTime End Get Set(value As Single) consumeTime = value End Set End Property '用来状态之间的切换 Public Sub SetState(ByVal s As State) current = s End Sub '运行金额计算功能 Public Sub WriteProgram() Me.current.WriteProgram(Me, money) End Sub End Class '抽象状态 'vb.Net中使用mustinheritkeyword来定义抽象类 Public MustInherit Class State 'vb.net中使用mustoverridekeyword来定义抽象方法 Public MustOverride Function WriteProgram(ByVal w As Work, money As Single) As Single End Class '表示准备时间状态 Public Class ForenoonState Inherits State Public Overrides Function WriteProgram(w As Work, money As Single) As Single '小于准备时间的话 If w.GetConsumeTime < 5 Then money = 0 '不用花钱 Else w.SetState(New NoonState()) w.WriteProgram() '运行下一个状态 End If Return money End Function End Class '表示至少上机时间状态 Public Class NoonState Inherits State Public Overrides Function WriteProgram(w As Work, money As Single) As Single If w.GetConsumeTime < 30 Then '小于至少上机状态的话 money = 5 '花费5元钱 Else w.SetState(New AfternoonState) w.WriteProgram() End If Return money End Function End Class '表示正常上机时间状态 Public Class AfternoonState Inherits State Public Overrides Function WriteProgram(w As Work, money As Single) As Single If w.GetConsumeTime > 60 Then '小于正常上机时间段的话 money = 4 / 60 * w.GetConsumeTime '计算金额 End If Return money End Function End Class
状态模式的长处
1.结构清晰
避免过多的switch……case或者if……else语句的使用。避免了程序的复杂性。提高了程序的可维护性
2.遵循设计原则
非常好的体现了开闭原则和单一职责原则。每一个状态都是一个子类,要改动的话,仅仅改动一个子类就可以
3.封装性好
状态变换放置到类的内部来实现,外部的调用不用知道类内部怎样实现状态和行为的变化