State

State design pattern allows object to manage its states while being operated asynchronously. This is commonly seen in web application or network implementation, where the client is holding a state of its condition when interacting with the server. The server responds accordingly to the client based on its given state of condition. Here is the design diagram:

Example (Solution)


package main

import (
        "fmt"
)

const (
        Guest     = 0
        User      = 1
        PowerUser = 2
        Admin     = 3
)

type Client struct {
        State int
        Name  string
        Data  string
        Err   string
}

func (c *Client) Printout() {
        fmt.Printf(`
CURRENT CONDITIONS
state  = %v
data   = %v
error  = %v
`,
                c.Name,
                c.Data,
                c.Err,
        )
}

type Server struct {
}

func (s *Server) Request(state int) (data string, err string) {
        switch state {
        case Guest:
                return "", "please login."
        case User:
                return "welcome to network.", ""
        case PowerUser:
                return "welcome to panel.", ""
        case Admin:
                return "welcome to controller.", ""
        }
        return "", "missing state"
}

func main() {
        s := &Server{}
        c := &Client{}

        c.Name = "guest"
        c.State = Guest
        c.Data, c.Err = s.Request(c.State)
        c.Printout()

        c.Name = "user"
        c.State = User
        c.Data, c.Err = s.Request(c.State)
        c.Printout()

        c.Name = "power-user"
        c.State = PowerUser
        c.Data, c.Err = s.Request(c.State)
        c.Printout()

        c.Name = "admin"
        c.State = Admin
        c.Data, c.Err = s.Request(c.State)
        c.Printout()
}

// Output:
//
// CURRENT CONDITIONS
// state  = guest
// data   = 
// error  = please login.
//
// CURRENT CONDITIONS
// state  = user
// data   = welcome to network.
// error  = 
//
// CURRENT CONDITIONS
// state  = power-user
// data   = welcome to panel.
// error  = 
//
// CURRENT CONDITIONS
// state  = admin
// data   = welcome to controller.
// error  = 

Notice that when the client changes from state to state, the server responded differently, giving different output. The client holds the state of a given time and condition. The serves accordingly with the given state.

Expected Outcome (Consequences)

  1. The control of condition is achieved via client.
  2. The server is serving based on the client's given condition.
  3. The server has no control over client's state in naive implementation.
    1. To overcome this, it is done securely by using encrypted and authenticated safe-box given to client instead of actual state value and the issuer of state is from the server, not the client.