欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 编程资源 > 编程问答 >内容正文

编程问答

Design Patterns(二十一):State Pattern--VB代码

发布时间:2025/3/19 编程问答 50 豆豆
生活随笔 收集整理的这篇文章主要介绍了 Design Patterns(二十一):State Pattern--VB代码 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

结构图

 

角色

  • 环境(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 DoubleByVal 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 DoubleByVal 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.0Me)
    
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代码的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。