首页 > 代码库 > 状态模式

状态模式

                             

定义


当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类。


状态模式的核心是封装,状态的变更引起了行为的变更,从外部看起来就好像这个对象对应的类发生了改变一样。通用类图如下:


 


1.State——抽象状态角色


接口或者抽象类,负责对象状态定义,并且封装角色以实现状态切换


2.ConcreteState——具体状态角色


每一个具体状态必须完成两个职责:本状态行为管理以及如何过渡到其他状态


3.Context——环境角色


定义客户端的接口,并且负责具体状态的切换


通用代码


  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中使用mustinherit关键字来定义抽象类
Public MustInherit Class State
    'vb.net中使用mustoverride关键字来定义抽象方法
    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.封装性好


状态变换放置到类的内部来实现,外部的调用不用知道类内部如何实现状态和行为的变化