Observer Class

You can post your code snippets here for others to use and learn from

Observer Class

Postby Bugala » Sun Aug 27, 2017 8:10 pm

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.
Bugala
 
Posts: 645
Joined: Sun Feb 14, 2010 8:11 pm

Return to Code snippets area

Who is online

Users browsing this forum: No registered users and 1 guest