近期在机房合作开发中,对状态模式又有了进一步的理解,下面就以机房收费系统为例子来学习装套模式
1. 状态模式基本概念
状态模式(State Pattern)是设计模式的一种,属于行为模式。
定义(源于Design Pattern):当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类。
状态模式主要解决的是当控制一个对象状态的条件表达式过于复杂时的情况。把状态的判断逻辑转移到表示不同状态的一系列类中,可以把复杂的判断逻辑简化。
意图:允许一个对象在其内部状态改变时改变它的行为
适用场景:
1.一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为。
2.一个操作中含有庞大的多 分支结构,并且这些分支决定于对象的状态。
2 结构图
3 结构图说明
- State 状态类 定义一个接口以封装与Context的一个特定状态相关的行为
- ConcreteState类 具体状态,每一个子类实现一个与Context的一个状态相关的行为
- Context类 维护一个ConcreteState子类的实例,这个实例定义当前的状态
4.状态模式的好处与用处
- 好处 :将与特定状态相关的行为局部化,并且将不同的状态行为分割开来,也就是将特定状态的相关行为都放在一个对象中,由于所有与状态相关的代码都存在于某个ConcreteState中,所以通过定义新的子类可以很容易的增加新的状态和转换,同时减少了相互之间的依赖
- 用处:当一个对象的行为取决于它的状态时,并且它必须在运行时刻根据状态改变它的行为时就可以考虑用状态模式
5.应用实例
看了上述的基础知识,应该对状态模式有了了解,那么如果想更深的了解状态模式,最好的办法就是
实践
可以说理解的在好,都不如实践例子来的实惠,懂得彻底
下面我就以机房收费系统系统中的登陆为例子 进行说明,对于登陆这个行为,我需要做如下的工作
- 判断用户名是否存在
- 判断密码是否存在
- 检查用户是否以在线
- 登陆成功将记录保存起来
这一些列的过程 其实也就符合了上面介绍的条件,因此应用状态模式来解决此问题,同时也增加了代码的灵活性
下面是结构图 :
四个子状态 即为登陆过程需要完成的事项
我在实现此过程中为状态设定了初始状态,也就是在LoginBLL中有一个私有的变量State 的初始值已经设定好了
实现此过程的代码 :
loginBLL类
''' <summary> ''' 定义一个状态变量 ''' </summary> Private State As LoginStateBLL ''' <summary> ''' 构造函数,初始化开始状态为判断用户名是否存在 ''' </summary> Public Sub New() State = New UserIsExistBLL() End Sub ''' <summary> ''' 设置状态 ''' </summary> ''' <param name="loginstate">传递用户登录过程中的状态</param> Public Function SetState(ByVal loginstate As LoginStateBLL) As LoginStateBLL State = loginstate '将当前状态值传递给全局变量state Return loginstate '将设置好的状态值返回 End Function ''' <summary> ''' 登录 ''' </summary> ''' <param name="enWork">工作记录实体</param> ''' <param name="enUser">用户实体</param> ''' <returns>登录成功返回true ''' 登录失败返回false</returns> ''' <remarks></remarks> Public Function Login(ByVal enWork As Entity.WorkEntity, ByVal enUser As Entity.UserEntiity) As Boolean Dim logins As LoginBLL = New LoginBLL '定义局部变量login 并实例化 Dim flag As Boolean = False '定义布尔类型变量 初始值为false '调用登陆状态类的方法 Try State.OnLog(logins, enWork, enUser) flag = True '登陆成功 Catch ex As Exception Throw New Exception(ex.Message) '捕捉登陆异常 ,并将异常抛出 End Try Return flag '将结果返回 End Function End Class
LoginStateBLL 类
Public Class LoginStateBLL ''' <summary> ''' 登录状态 ''' </summary> ''' <param name="login">登录</param> ''' <param name="enWork">工作实体</param> ''' <param name="enUser">用户实体</param> Public Overridable Sub OnLog(ByVal login As LoginBLL, ByVal enWork As Entity.WorkEntity, ByVal enUser As Entity.UserEntiity) End Sub End Class
四个子状态类 其中之一如下 :
UserIsExistBLL类
-
''' <summary> ''' 判断用户名是否存在 ''' </summary> Public Class UserIsExistBLL Inherits BLL.LoginStateBLL ''' <summary> ''' 登录状态 判断用户名是否存在 ''' </summary> ''' <param name="login">登录</param> ''' <param name="enWork">工作实体</param> ''' <param name="enUser">用户实体</param> Public Overrides Sub OnLog(ByVal login As LoginBLL, ByVal enWork As Entity.WorkEntity, ByVal enUser As Entity.UserEntiity) Dim factory As DFactory.DataAccess = New DFactory.DataAccess '定义并实例化工厂 Dim IUser As IDAL.IUser '定义接口 IUser = factory.GetUser() '调用工厂方法创建接口 Dim BTable As New DataTable '定义变量datatable BTable = IUser.IUserIsExit(enUser) '调用接口方法查询用户名是否存在 '判断用户名是否存在即表中是否含有所要查找的数据 If BTable.Rows.Count = 0 Then Throw New Exception("该用户名不存在") '抛出异常 Else login.SetState(New PwdIsExistBLL) '调用下一个状态 login.Login(enWork, enUser) '调用loginBLL中的登陆方法 End If End Sub End Class
其余的子状态类的写法与这个大致相同,应用状态模式依次的执行每个状态,执行完毕后返回,这样也完成了登陆功能 。在上述参考代码中 loginBLL中 我要通过设置状态方法来设置每次要执行的状态是什么,然后将该状态传递给登陆的方法 也就可以完成这个过程了
对于状态模式的应用以及理解,敲一个例子,大概也就理解的八九不离十了,以上就是我对状态模式的学习过程,以及一些总结,不足之处请多多指教!