结构图

角色

  • 环境(Subject)角色:负责定义客户感兴趣的接口,并维护一个具体状态(ConcreteState)的实例,以及维护状态转换或为这种转换提供支持(因为状态转换有时候可能是由上层应用发起的)。
  • 状态(State)角色:定义一个接口以封装与环境(Context)角色的一个特定状态相关的行为。
  • 具体状态(ConcreteState)角色:)每一个子类实现一个与环境(Context)角色状态相关的行为。

动机

  在软件构建过程中,某些对象的状态如果改变,其行为也会随之而发生变化,比如文档处于只读状态,其支持的行为和读写状态支持的行为就可能完全不同。
     如何在运行时根据对象的状态来透明地更改对象的行为?而不会为对象操作和状态转化之间引入紧耦合?

意图

允许一个对象在其内部状态改变时改变它的行为。从而使对象看起来似乎修改了其行为。

示意性代码

示意性代码
'State pattern -- Structural example

'MainApp test application
Module MainApp
    Public Sub Main()
        'Setup context in a state
        Dim c As New Context(New ConcreteStateA)

'Issue requests, which toggles state
        c.Request()
        c.Request()
        c.Request()
        c.Request()

'Wait for user 
        Console.ReadLine()
    End Sub
End Module

'"State"
Public MustInherit Class State
    Public MustOverride Sub Handle(ByVal context As Context)
End Class

'"ConcreteStateA"
Public Class ConcreteStateA
    Inherits State
    Public Overrides Sub Handle(ByVal context As Context)
        context.State = New ConcreteStateB
    End Sub
End Class

'"ConcreteStateB"
Public Class ConcreteStateB
    Inherits State
    Public Overrides Sub Handle(ByVal context As Context)
        context.State = New ConcreteStateA
    End Sub
End Class

'"Context"
Public Class Context
    'Constructor 
    Public Sub New(ByVal state As State)
        Me._state = state
    End Sub

'Property
    Private _state As State
    Public Property State() As State
        Get
            Return _state
        End Get
        Set(ByVal value As State)
            _state = value
        End Set
    End Property

Public Sub Request()
        State.Handle(Me)
    End Sub
End Class

 一个实例

下面的状态模式代码演示了一个帐户在处于不同状态时可以进行不同的操作。在行为上的区别委派给以下三个对象红色状态(RedState),灰色状态(SilverState),金色状态(GoldState)。这些状态分别代表透支帐户,新开通的帐户,和拥有良好信誉的帐户。

旧系统代码
'State pattern -- Real World example

'MainApp test application
Module MainApp
    Public Sub Main()
        'Open a new account
        Dim account As New Account("Jim Johnson")

'Apply financial transactions
        account.Deposit(500.0)
        account.Deposit(300.0)
        account.Deposit(550.0)
        account.PayInterest()
        account.Withdraw(2000.0)
        account.Withdraw(1100.0)

'Wait for user
        Console.ReadLine()
    End Sub
End Module

'"Context"
Public Class Account
    Private owner As String
    Private serviceFee As Double
    Private interest As Double

'Constructor
    Public Sub New(ByVal owner As String)
        'New accounts are 'Silver' by default
        Me.owner = owner
        _state = "SilverState"
    End Sub

'Properties
    Protected _balance As Double
    Public ReadOnly Property Balance() As Double
        Get
            Return _balance
        End Get
    End Property

Private _state As String
    Public Property State() As String
        Get
            Return _state
        End Get
        Set(ByVal value As String)
            _state = value
        End Set
    End Property

Public Sub Deposit(ByVal amount As Double)
        _balance += amount
        StateChangeCheck()
        Console.WriteLine("Deposited {0:C} --- ", amount)
        Console.WriteLine(" Balance = {0:C}", Me.Balance)
        Console.WriteLine(" Status = {0}", _
         _state)
        Console.WriteLine("")
    End Sub

Public Sub Withdraw(ByVal amount As Double)
        If _state = "RedState" Then
            serviceFee = 15.0
            amount -= serviceFee
            Console.WriteLine("No funds available for withdrawal!")
        Else
            _balance -= amount
        End If
        StateChangeCheck()
        Console.WriteLine("Withdrew {0:C} --- ", amount)
        Console.WriteLine(" Balance = {0:C}", Me.Balance)
        Console.WriteLine(" Status = {0}", _
         _state)
        Console.WriteLine("")
    End Sub

Public Sub PayInterest()
        Select Case _state
            Case "RedState"
                'No Interest is paid
            Case "SilverState"
                interest = 0.0
                _balance += interest * _balance
            Case "GoldState"
                interest = 0.05
                _balance += interest * _balance
        End Select

Console.WriteLine("Interest Paid --- ")
        Console.WriteLine(" Balance = {0:C}", Me.Balance)
        Console.WriteLine(" Status = {0}", _
         _state)
        Console.WriteLine("")
    End Sub

Private Sub StateChangeCheck()
        If Balance < 0.0 Then
            _state = "RedState"
        ElseIf _balance < 1000 Then
            _state = "SilverState"
        Else
            _state = "GoldState"
        End If
    End Sub
End Class

在开发中时常遇到的根据不同的状态需要进行不同的处理操作的问题,而这样的问题,大部分人是采用Select-Case/If-Else语句进行处理的,这样会造成一个问题:分支过多,而且如果加入一个新的状态就需要对原来的代码进行编译.State模式采用了对这些不同的状态进行封装的方式处理这类问题,当状态改变的时候进行处理然后再切换到另一种状态,也就是说把状态的切换责任交给了具体的状态类去负责.具体的状态类可以通过派生的方式不依赖于其他对象而独立变化。

运用模式后的代码
'State pattern -- Real World example

'MainApp test application
Module MainApp
    Public Sub Main()
        'Open a new account
        Dim account As New Account("Jim Johnson")

'Apply financial transactions
        account.Deposit(500.0)
        account.Deposit(300.0)
        account.Deposit(550.0)
        account.PayInterest()
        account.Withdraw(2000.0)
        account.Withdraw(1100.0)

'Wait for user
        Console.ReadLine()
    End Sub
End Module

'"State"
Public MustInherit Class State
    'Fields
    Protected interest As Double
    Protected lowerLimit As Double
    Protected upperLimit As Double

'Properties
    Protected _account As Account
    Public Property Account() As Account
        Get
            Return _account
        End Get
        Set(ByVal value As Account)
            _account = value
        End Set
    End Property

Protected _balance As Double
    Public Property Balance() As Double
        Get
            Return _balance
        End Get
        Set(ByVal value As Double)
            _balance = value
        End Set
    End Property

Public MustOverride Sub Deposit(ByVal amount As Double)
    Public MustOverride Sub Withdraw(ByVal amount As Double)
    Public MustOverride Sub PayInterest()
End Class

'"ConcreteState"
'Account is overdrawn
Public Class RedState
    Inherits State

Private serviceFee As Double

'Constructor
    Public Sub New(ByVal state As State)
        Me.Balance = state.Balance
        Me.Account = state.Account
        Initialize()
    End Sub

Private Sub Initialize()
        'Should come from a datasource
        interest = 0.0
        lowerLimit = -100.0
        upperLimit = 0.0
        serviceFee = 15.0
    End Sub

Public Overrides Sub Deposit(ByVal amount As Double)
        Balance += amount
        StateChangeCheck()
    End Sub
    Public Overrides Sub Withdraw(ByVal amount As Double)
        amount -= serviceFee
        Console.WriteLine("No funds available for withdrawal!")
    End Sub
    Public Overrides Sub PayInterest()
        'No intereset is paid
    End Sub
    Private Sub StateChangeCheck()
        If Balance > upperLimit Then
            Account.State = New SilverState(Me)
        End If
    End Sub
End Class

'"ConcreteState"
'Silver is non-interest bearing state
Public Class SilverState
    Inherits State

'Overloaded constructors
    Public Sub New(ByVal state As State)
        Me.new(state.Balance, state.Account)
    End Sub

Public Sub New(ByVal balance As Double, ByVal account As Account)
        Me.Balance = balance
        Me.Account = account
        Initialize()
    End Sub
    Private Sub Initialize()
        'Should come from a datasource
        interest = 0.0
        lowerLimit = 0.0
        upperLimit = 1000.0
    End Sub

Public Overrides Sub Deposit(ByVal amount As Double)
        Balance += amount
        StateChangeCheck()
    End Sub
    Public Overrides Sub Withdraw(ByVal amount As Double)
        Balance -= amount
        StateChangeCheck()
    End Sub
    Public Overrides Sub PayInterest()
        Balance += interest * Balance
        StateChangeCheck()
    End Sub
    Private Sub StateChangeCheck()
        If Balance < lowerLimit Then
            Account.State = New RedState(Me)
        ElseIf Balance > upperLimit Then
            Account.State = New GoldState(Me)
        End If
    End Sub
End Class

'"ConcreteState"
'Interest bearing state
Public Class GoldState
    Inherits State

'Overloaded constructors
    Public Sub New(ByVal state As State)
        Me.new(state.Balance, state.Account)
    End Sub

Public Sub New(ByVal balance As Double, ByVal account As Account)
        Me.Balance = balance
        Me.Account = account
        Initialize()
    End Sub
    Private Sub Initialize()
        'Should come from a datasource
        interest = 0.05
        lowerLimit = 1000.0
        upperLimit = 10000000.0
    End Sub

Public Overrides Sub Deposit(ByVal amount As Double)
        Balance += amount
        StateChangeCheck()
    End Sub
    Public Overrides Sub Withdraw(ByVal amount As Double)
        Balance -= amount
        StateChangeCheck()
    End Sub
    Public Overrides Sub PayInterest()
        Balance += interest * Balance
        StateChangeCheck()
    End Sub
    Private Sub StateChangeCheck()
        If Balance < 0.0 Then
            Account.State = New RedState(Me)
        ElseIf Balance < lowerLimit Then
            Account.State = New SilverState(Me)
        End If
    End Sub
End Class

'"Context"
Public Class Account
    Private owner As String

'Constructor
    Public Sub New(ByVal owner As String)
        'New accoounts are 'Silver' by default
        Me.owner = owner
        _state = New SilverState(0.0, Me)
    End Sub

'Properties
    Public ReadOnly Property Balance() As Double
        Get
            Return _state.Balance
        End Get
    End Property

Private _state As State
    Public Property State() As State
        Get
            Return _state
        End Get
        Set(ByVal value As State)
            _state = value
        End Set
    End Property

Public Sub Deposit(ByVal amount As Double)
        State.Deposit(amount)
        Console.WriteLine("Deposited {0:C} --- ", amount)
        Console.WriteLine(" Balance = {0:C}", Me.Balance)
        Console.WriteLine(" Status = {0}", _
         _state.GetType().Name)
        Console.WriteLine("")
    End Sub

Public Sub Withdraw(ByVal amount As Double)
        State.Withdraw(amount)
        Console.WriteLine("Withdrew {0:C} --- ", amount)
        Console.WriteLine(" Balance = {0:C}", Me.Balance)
        Console.WriteLine(" Status = {0}", _
         _state.GetType().Name)
        Console.WriteLine("")
    End Sub

Public Sub PayInterest()
        _state.PayInterest()
        Console.WriteLine("Interest Paid --- ")
        Console.WriteLine(" Balance = {0:C}", Me.Balance)
        Console.WriteLine(" Status = {0}", _
         Me.State.GetType().Name)
        Console.WriteLine("")
    End Sub
End Class

State Pattern模式的几个要点:
   1、State模式将所有与一个特定状态相关的行为都放入一个State的子类对象中,在对象状态切换时,切换相应的对象;但同时维持State的接口,这样实现了具体操作与状态转换之间的解耦。
   2、为不同的状态引入不同的对象使得状态转换变得更加明确,而且可以保证不会出现状态不一致的情况,因为转换是原子性的——即要么彻底转换过来,要么不转换。
     3、如果State对象没有实例变量,那么各个上下文可以共享一个State对象,从而节省对象开销。

我的理解

封装与状态相关的行为,支持状态的变化。

参考资料
《C#面向对象设计模式纵横谈系列课程(21)》     李建中老师

Design Patterns(二十一):State Pattern--VB代码相关推荐

  1. 检索com类工厂 80070005_Hands-On Design Patterns With C++(十二)友元工厂

    目录: trick:Hands-On Design Patterns With C++(零)前言​zhuanlan.zhihu.com 友元工厂 c++中,友元用于给予其他类访问权限.本章具体讨论以下 ...

  2. Decorator Pattern - C# 3.0 Design Patterns

    Decorator Pattern属于Structural Patterns 介绍: Decorator pattern的作用是提供一种方式动态的给一个对象添加新的职责或状态,被装饰的对象并不知道被& ...

  3. 状态设计模式(State Pattern)[论点:概念、相关角色、图示、示例代码、框架中的运用、适用场景]

    文章目录 概念 组成角色 相关图示 代码示例 框架中的应用 适用场景 概念 状态模式(State Pattern)是一种行为型设计模式,用于解决对象在不同状态下的行为问题.它允许一个对象在其内部状态改 ...

  4. LinuxGUI自动化测试框架搭建(二十一)-截止第二十篇,如果出现以下错误,请修改代码+截止目前的全局配置文件config.py内容

    (二十一)-截止第二十篇,如果出现以下错误,请修改代码 1 错误类型 2 原因分析 3 解决方法 4 修改common/screenShot.py 5 修改config/config.py 1 错误类 ...

  5. 设计模式(Design Patterns)详解

    设计模式(Design Patterns) --可复用面向对象软件的基础一般会用到的: Factory( 工厂模式) Singleton(单例模式) 这两个比较多 Proxy(代理模式) Adapte ...

  6. Java23中设计模式(Design Patterns)详解

    2019独角兽企业重金招聘Python工程师标准>>> 设计模式(Design Patterns) --可复用面向对象软件的基础 设计模式(Design pattern)是一套被反复 ...

  7. C# Design Patterns (3) - Decorator

    本帖介绍 Decorator Pattern (装饰模式),文章最后另提供 Decorator Pattern 的趣味四格漫画. ----------------------------------- ...

  8. 艾伟_转载:C# Design Patterns (3) - Decorator

    Decorator Pattern (装饰模式) 装饰模式可「动态」地给一个对象添加一些额外的职责,提供有别于「继承」的另一种选择.就扩展功能而言,Decorator Pattern 透过 Aggre ...

  9. Design patterns 设计模式

    Christopher Alexander 说过:"每一个模式描述了一个在我们周围不断重复发生的问题,以及该问题的解决方案的核心.这样,你就能一次又一次地使用该方案而不必做重复劳动" ...

最新文章

  1. Python解析照片EXIF信息,获取坐标位置
  2. 如何让Keil MDK兼容Keil C51?
  3. 计算机vb操作题评分细则,上机考试的试题及评分标准.doc
  4. 如何给网页标题添加icon小图标
  5. 宝宝的成长脚印9/29
  6. 什么是在Vim中评论/取消注释行的快速方法?
  7. 退出所有循环_探索未知种族之osg类生物---呼吸分解之事件循环三
  8. linux中级之HAProxy基础配置
  9. tl-wdr5620千兆版设置虚拟服务器,TP-LINK无线路由TL-WDR5620千兆版使用步骤图解
  10. 基于C#的“密码学”实验演示系统的设计与实现、.NET下的RSA编程、各种密码学算法的C# GUI编程实现
  11. python统计词频瓦尔登湖_点评《瓦尔登湖》
  12. 6.Java设计模式之设配器模式
  13. 基于3D Sensor的触控与悬控高性能方案
  14. 易语言取文件名和文件扩展名
  15. PINN解偏微分方程实例3(Allen-Cahn方程)
  16. 如何将pip更新到最新版本
  17. 如何给网站做SEO优化?
  18. OpenCV4.x图像处理实例-自动包围曝光(Auto Exposure Bracketing,AEB)
  19. android 仿qq好友动态,Android UI仿QQ好友列表分组悬浮效果
  20. shell终端多目录间快速cd工具

热门文章

  1. 【业务知识】档案数字化加工处理过程
  2. Java基础 集合(Collection)结构详解 Collection和Collections的区别
  3. Linux系统高并发kernel参数优化
  4. linux服务端搭配win7客户端的frp
  5. 信息系统项目管理师-信息系统安全管理核心知识思维脑图
  6. Android中使用retrofit2进行网络get请求查询数据和post请求上传文件
  7. SpringBoot+Jquery实现前后端数据交互
  8. 企业架构(五)——联邦企业架构(FEA)实施指南
  9. TOC之关键链项目管理遇到软件工程7原则
  10. BUG You have an error in your SQL syntax; check