Search code examples
coffeescriptobserver-pattern

How to implement an observer with coffeescript


I try to implement the observer pattern in coffeescript like wikipedia observer pattern. How can this be done with coffeescript?


Solution

  • Create a class like this:

    class Observer
      constructor: () ->
        @subscribers = {}
      notify: (to, arg...) ->
        if @subscribers[to]
          for cb in @subscribers[to].callback 
            try
              cb.apply @,[to].concat arg
            catch err
              console.log to+" "+(arg?.join ', ')+": "+err
      subscribe: (to, cb) ->
        if @subscribers[to]==undefined || @subscribers[to].callback.size==0
          @subscribers[to]={'callback':[cb]}
        else
          @subscribers[to].callback.push cb if cb not in @subscribers[to].callback
      unsubscribe: (to, cb) ->
        @subscribers[to]?.callback.splice @subscribers[to].callback.indexOf(cb), 1
    

    How to use

    ### Define subscriber ###
    class SubscriberA
      onEvent: (item) ->
        console.log item
    
    class SubscriberB
      onEvent: (item) ->
        console.log item
    
    class SubscriberC
      onEventTypeA: (item) ->
        console.log "EventTypeA: "+item
    
      onEventTypeB: (item) ->
        console.log "EventTypeB: "+item
    
    class SubscriberD
      onEventTypeA: (item,arg="23 is default") ->
        console.log item+" "+arg
      onEventTypeB: (item,arg...) ->
        console.log item + " with: "
        for a in arg
          console.log a
    
    ### Create observer ###
    myO = new Observer()
    
    ### Create subscribing objects
       In real live this would be your objects that will have to provide a function that handels notifications. Within this example they are called onEventXYZ
    ###
    subscriptionOfA = new SubscriberA()
    subscriptionOfB = new SubscriberB()
    subscriptionOfC = new SubscriberC()
    subscriptionOfD = new SubscriberD()
    
    console.log ": Subscribe Peter once and Paul twice"
    myO.subscribe "Peter", subscriptionOfA.onEvent
    myO.subscribe "Paul", subscriptionOfA.onEvent
    myO.subscribe "Paul", subscriptionOfA.onEvent
    
    console.log ": Notify Peter and Paul"
    myO.notify "Peter"
    myO.notify "Paul"
    
    console.log ": Paul is only notified once as duplicate subscriptions are ignored while subscribe"
    console.log ": Subscribe Paul with a different subscriber"
    myO.subscribe "Paul", subscriptionOfB.onEvent
    console.log ": Notify Peter and Paul"
    myO.notify "Peter"
    myO.notify "Paul"
    
    console.log ": Paul is notified twice as two different subscriptions are subscribed"
    
    console.log "\n: Unsubscribe Peter"
    myO.unsubscribe "Peter"
    console.log ": Notify Peter and Paul"
    myO.notify "Peter"
    myO.notify "Paul"
    
    
    console.log "\n: Not subscribed items will be ignored at notify"
    console.log ": Notify Bob"
    myO.notify "Bob"
    
    console.log "\n: You may use multiple eventHandler in your subsribers"
    
    myO.subscribe "Mary", subscriptionOfC.onEventTypeA
    myO.subscribe "Jane", subscriptionOfC.onEventTypeB
    
    console.log ": Notify Mary and Jane"
    myO.notify "Mary"
    myO.notify "Jane"
    
    console.log "\n: You may use arguments with your eventHandler"
    
    myO.subscribe "Laurel", subscriptionOfD.onEventTypeA
    myO.subscribe "Hardy", subscriptionOfD.onEventTypeB
    
    console.log ": Notify Laurel without argument"
    myO.notify "Laurel"
    console.log ": Notify Laurel with argument"
    myO.notify "Laurel", 42
    console.log ": Notify Hardy with multiple arguments"
    myO.notify "Hardy", "Argument String",1,2,3,['a','b']