Observer Class

You can post your code snippets here for others to use and learn from
Post Reply
Bugala
Posts: 1168
Joined: Sun Feb 14, 2010 7:11 pm

Observer Class

Post by Bugala »

I am sharing my Observer class so others can use it too if they wish. This is my hollywood version of so called Observer Pattern.

Observer is an alternative to global IF statements that are often used as Gamestate = #SOMETHING.
I might write a tutorial regarding this one day.

Code: Select all

Observer = { table = {} }

Function Observer:Add(name, message, func, ...) /* ... part are possible arguments */
   self.table[name] = { message=message, func=func, arg=arg }
EndFunction


Function Observer:Remove(name)
   self.table[name] = Nil
EndFunction

Function Observer:Execute(name)
   subtable = self.table[name]
   arg = subtable.arg
   subtable.func(Unpack(arg))   
EndFunction



Function Observer:Inform(message)
   For name, itemtable In Pairs(self.table)
      If itemtable.message = message Then observer:execute(name)
   Next
EndFunction


Function Observer:ListObservers() /* This is simply for debugging reasons */
	ForEach(observer.table, DebugPrint)
EndFunction
And here is example code using this (dont forget to add the previous code at beginning or it wont work):

Code: Select all

Function card1(n)

Local temptable = {
      [1] = { funcinadvance = init_up, name="card1", message="up is done", func=card1, arg=2,  },
      [2] = { funcinadvance = Init_down, name="card1", message="down is done", func=card1, arg=3,   },
      [3] = { funcinadvance = init_up, name="card1", message="up is done", func=card1, arg=4,  },
      [4] = { funcinadvance = Init_down, name="card1", message="down is done", func=card1, arg=5,   },
      [5] = { funcinadvance = init_up, name="card1", message="up is done", func=card1, arg=6,  },
      [6] = { funcinadvance = Init_down, name="card1", message="down is done", func=card1, arg=7,   },
      [7] = { funcinadvance = init_up, name="card1", message="up is done", func=card1, arg=8,  },
      [8] = { funcinadvance = Init_down, name="card1", message="down is done", func=card1, arg=9,   },
      [9] = { funcinadvance = init_up, name="card1", message="up is done", func=card1, arg=10,  }
	       }

If n = 0 Then n=1
observer:remove("card1")

If n < 10
   temptable[n].funcinadvance()
   
   name="card1"
   message = temptable[n].message
   func = temptable[n].func
   arg = temptable[n].arg
   
   observer:add(name, message, func, arg)   
EndIf

EndFunction


Function init_upcounter()
   var_upcounter = 0
   TextOut(100, 300, "upcounter: "..var_upcounter, {name="upcounterlayer"} )
   observer:add("upcounter", "up is done", upcounter)
EndFunction


Function upcounter()
   var_upcounter=var_upcounter + 1
   SetLayerStyle("upcounterlayer", {text="upcounter: "..var_upcounter} )
   If var_upcounter = 3 
   observer:remove("upcounter")
   EndIf
EndFunction


Function init_up()
   TextOut(300, 300, "press up", {name="up"})
   SetInterval(2, up, 15)
EndFunction


Function up()

   Local pressed = False

   If IsKeyDown("UP") = True Then pressed = True

   If pressed = True
      RemoveLayer("up")
      ClearInterval(2)
      Observer:inform("up is done")
   EndIf

EndFunction


Function init_down()
   TextOut(300, 400, "press down", {name="down"})
   SetInterval(3, down, 15)
EndFunction   


Function Down()
   
   Local pressed = False

   If IsKeyDown("DOWN") = True Then pressed = True
   If pressed = True
      RemoveLayer("down")
      ClearInterval(3)
      Observer:inform("down is done")
   EndIf

EndFunction




Function updategraphics()
   If dir = 0 Then x=x-3
   If dir = 1 Then x=x+3
   If x <100 Then dir = 1
   If x >500 Then dir = 0
   SetLayerStyle("text1", {x=x})
EndFunction



EnableLayers

TextOut(100, 100, "moving text", {name="text1"})

SetInterval(1, UpdateGraphics, 15)
card1()
init_upcounter()

Repeat
   WaitEvent()
Forever

This works the following.

To add something to be Observed, is to use:

Code: Select all

Observer:Add(name, message, function, args)
NAME is any name you choose to use for your observer. Name is important in sense that you can at later point use to remove that Observer based upon its name. Also, you should avoid having two Observers with same name hanging in list.

MESSAGE is the message that this observer is waiting for before it starts executing its FUNCTION.

FUNCTION is the function that will be executed if observer receives the MESSAGE.

ARGS are one or more args (it uses ...) that are going to be passed to the FUNCTION when MESSAGE is received.


then somewhere in your code needs to be:

Code: Select all

Observer:Inform(message)
Where MESSAGE is the message that one or more observers are waiting for. This command will go through all observers currently in list and if one or more of them are waiting for that specific message, it will then execute the function given.

Code: Select all

Observer:Remove(name)
will simply remove observer from list that is listed under the given NAME.

Code: Select all

Observer:ListObservers()
This is simply for debugging reasons and will list every observer currently on list with the message they are waiting for.
Post Reply