State pattern is probably most used in review cycles. The definition says:

State pattern allows an object to appear as it can change its class by altering its behaviour and state.

What are you talking about?

Well, imagine you are in need to build a bug tracking database.  Bug reports in basics have four states. First they are unassigned until someone is solving them. When they are taken over, they become assigned, specifying that someone is already working on them. After bug fix has been produced, it is a good practice to send it to testing. Then it is up to QA to confirm that bug fix is complete or whether it is not.

Show me the code!

Example will be based on simple bug report specified above. However, I will skip actual action implementation as it varies based on application needs. Instead, I will use message box to print out the action report.

So, now, first what you need is a state abstract class that will implement all methods needed for transition between states (in our case: unassigned, assigned, send to testing and complete).

Class CState
	Sub TakeOver()
	End Sub

	Sub SendToTesting()
	End Sub

	Sub Complete()
	End Sub
End Class

Then, what you need is a context class that will be used when changing state of a bug report.

Class CStateBugReport
   stateUnassigned As CState
   stateAssigned As CState
   stateReadyForTesting As CState
   stateCompleted As CState
   stateCurrent As CState

   Sub New
      Set stateUnassigned = New CStateUnassigned (Me)
      Set stateAssigned = New CStateAssigned (Me)
      Set stateReadyForTesting = New CStateSentToTesting (Me)
      Set stateCompleted = New CStateCompleted (Me)

      Set stateCurrent = stateUnassignedb
   End Sub

   Sub Assign()
      Call stateCurrent.TakeOver()
   End Sub

   Sub SendToTesting()
      Call stateCurrent.SendToTesting()
   End Sub

   Sub Complete()
      Call stateCurrent.Complete()
   End Sub

   Function GetAssignedState() As CState
      Set GetAssignedState = stateAssigned
   End Function

   Function GetReadyForTestingState() As CState
      Set GetReadyForTestingState = stateReadyForTesting
   End Function

   Function GetCompletedState() As CState
      Set GetCompletedState = stateCompleted
   End Function

   Sub SetState( state As CState )
      Set Me.stateCurrent = state
   End Sub
End Class

And now, we need to implement all four states classes.

Class CStateUnassigned As CState
   bugReport As CStateBugReport

   Sub New (bugReport As CStateBugReport)
      Set Me.bugReport = bugReport
   End Sub

   Sub TakeOver ()
      Messagebox "Took over!"
      Call Me.bugReport.SetState (Me.bugReport.GetAssignedState())
   End Sub

   Sub SendToTesting()
      Messagebox "Unassigned reports cannot be sent to testing"
   End Sub

   Sub Complete()
      Messagebox "Unassigned reports cannot be completed"
   End Sub
End Class

Class CStateAssigned As CState
   bugReport As CStateBugReport

   Sub New (bugReport As CStateBugReport)
      Set Me.bugReport = bugReport
   End Sub

   Sub TakeOver ()
      Messagebox "Report already assigned"
   End Sub

   Sub SendToTesting()
      Messagebox "Sent to testing!"
      Call Me.bugReport.SetState
         (Me.bugReport.GetReadyForTestingState())
   End Sub

   Sub Complete()
      Messagebox "Untested reports cannot be completed"
   End Sub
End Class

Class CStateSentToTesting As CState
   bugReport As CStateBugReport

   Sub New (bugReport As CStateBugReport)
      Set Me.bugReport = bugReport
   End Sub

   Sub TakeOver ()
      Messagebox "Report already assigned"
   End Sub

   Sub SendToTesting()
      Messagebox "Report already in testing"
   End Sub

   Sub Complete()
      Messagebox "Complete!"
      Call Me.bugReport.SetState (Me.bugReport.GetCompletedState())
   End Sub
End Class

Class CStateCompleted As CState
   bugReport As CStateBugReport

   Sub New (bugReport As CStateBugReport)
      Set Me.bugReport = bugReport
   End Sub

   Sub TakeOver ()
      Messagebox "Report already completed"
   End Sub

   Sub SendToTesting()
      Messagebox "Report already completed"
   End Sub

   Sub Complete()
      Messagebox "Report already completed"
   End Sub
End Class

This is all there is to it. To test it, I wrote a simple agent that goes through states and in each new state also tests wrong transitions (e.g. from unassigned to complete etc.).

Sub Initialize
	Dim bugReport As New CStateBugReport()

	Call bugReport.SendToTesting()
	Call bugReport.Complete()

	Call bugReport.Assign()
	Call bugReport.Assign()
	Call bugReport.Complete()

	Call bugReport.SendToTesting()
	Call bugReport.Assign()
	Call bugReport.SendToTesting()

	Call bugReport.Complete()
	Call bugReport.Assign()
	Call bugReport.SendToTesting()
	Call bugReport.Complete()
End Sub