"Observer pattern" is the term given to the programming construct of a notification system implemented within your application. It's a very powerful tool that can be very useful when dealing with non-deterministic events. For example, mouse clicks can come in at any point in time -- you never know when one will come. You can use the observer pattern to have one part of your application notify another part that a mouse click has occurred.
In the preceeding example, the object that notices the mouse clicks and is responsible for firing off the notification is what I call the "observeable object" or "observed object." The objects that are notified of the event are the "observers." The general principle is that an observer will let an observeable object know that it's being watched. When the observeable object has an event, then it alerts all the observers of it.
Now that you know a bit more about what should be happening, let's discuss a generic way to make it all work.
Interfaces. Observeable objects implement an interface so that there is a generic way for someone to say "I want to watch you, please let me know when something interesting happens." Similarly, the observer needs to implement an interface so that there's a generic way for the observeable object to alert all the observers that something interesting has happened.
Let's take things one step at a time. We'll start off with the observer's interface since it should be quite simple. For the sake of convention, I typically name all my interfaces ISomething so that I know when I am dealing with an interface. This is just a naming convention -- you're welcome to deviate from it if you'd like.
The observer only needs one method, which is the one the oberved object will call when something interesting happens.
[rbcode]
Interface IObserver
Sub Notify()
End Sub
End Interface
[/rbcode]
Phew! That was pretty easy! You see, any time an event happens, the observed object simply needs to call Notify on all of the observers it knows about. But let's make this a little more powerful. An observer may be observing multiple events from different objects, so we should provide a way to keep track of what object spawned which event. We'll also throw in a way for the observer to say "stop sending this notification." Now our interface will look more like this:
[rbcode]
Interface IObserver
Function Notify( fromWho as IObserveable, eventName as String ) as Boolean
End Function
End Interface
[/rbcode]
So what does the IObserveable interface look like then? Remember, this is the interface which says "I can be observed." It's the way to hook an IObserver to an IObserveable object.
[rbcode]
Interface IObserveable
Sub Observe( observer as IObserver, eventName as String )
End Sub
End Interface
[/rbcode]
You'll notice that we're passing in an IObserver -- this is so that we know who to notify when something interesting happens. That something interesting is defined by the eventName as also pass in.
Now comes the fun part -- making these abstract concepts do something useful. Let's make two example classes and see how this may work.
[rbcode]
Class SpiffyClassOne Implements IObserver
Dim mObserved as SomeOtherClass
Function Notify( fromWho as IObserveable, eventName as String ) as Boolean
// Something interesting happened
if eventName = "Foobar" then MsgBox "Foobar happened"
return false
End Function
Sub Constructor()
// Make an instance of the class
mObserved = new SomeOtherClass
// And observe it
mObserved.Observe( self, "Foobar" )
End Sub
End Class
Class SomeOtherClass Implements IObserveable
Dim mObserver as IObserver
Sub Observe( observer as IObserver, eventName as String )
mObserver = observer
End Sub
Sub DoFoobar()
dim foobar as Integer = 12
foobar = foobar + MagicGlobalWahoo
if mObserver <> nil then mObserver.Notify( self, "Foobar" )
End Sub
End Class
[/rbcode]
As you can see, both classes satisfy the contracts from the Observer pattern interfaces. And whenever the DoFoobar method gets call, the observer pattern kicks in and the observer is notified of the event. But there are some obvious flaws to the code (aside from it being a very contrived example). For instance, the SomeOtherClass only keeps track of one observer, but there could be many classes observing this single object. That means you'll need a list of observers. But, not just one list since different observers may be observing the object for different events. As you can see, this could get quickly out of hand. But that's why I came up with a helper class: to make it easy to keep track of all the little details about who's observing you and why. The helper class needs to keep track of a few pieces of information, such as what event name, who the observed class is as well as a list of observers for that information.
[rbcode]
Class ObserverList
Private Dim mEventName as String
Private Dim mFromWho as IObserveable
Protected Dim mObserverList(-1) as IObserver
Sub Constructor( eventName as String, fromWho as IObserveable )
// Store our information for later
mEventName = eventName
mFromWho = fromWho
End Sub
Sub AddNewObserver( observer as IObserver )
// Always add the observer on to the
// front of the list, that way the last observer
// added is the first one called
mObserverList.Insert( 0, observer )
End Sub
Sub NotifyObservers()
// Loop over all the observers and notify them
// that an event has happened
dim observer as IObserver
for each observer in mObserverList
if observer.Notify( mFromWho, mEventName ) = true then
// We're supposed to stop notifying
return
end if
next observer
End Sub
End Class
[/rbcode]
Now things should be a little easier because we've got a helper class that takes care of mapping event names to observer lists. So how would we use one of these? Let's modify our code from before. We only need to modify the observeable object since that's what's responsible for notifying the observers.
[rbcode]
Class SomeOtherClass Implements IObserveable
Dim mFoobarObserverList, mBarBazObserverList as ObserverList
Sub Constructor()
// Make an observer list for the Foobar and BarBaz events
mFoobarObserverList = new ObserverList( "Foobar", self )
mBarBazObserverList = new ObserverList( "BarBaz", self )
End Sub
Sub Observe( observer as IObserver, eventName as String )
select case eventName
case "Foobar"
mFoobarObserverList.AddNewObserver( observer )
case "BarBaz"
mBarBazObserverList.AddNewObserver( observer )
else
raise new RuntimeException // Replace this with something more sensible
end select
End Sub
Sub DoFoobar()
dim foobar as Integer = 12
foobar = foobar + MagicGlobalWahoo
mFoobarObserverList.NotifyObservers
End Sub
Sub DoBarBaz()
// Do the BarBaz action dance
DoActionDance
// Alert
mBarBazObserverList.NotifyObservers
End Sub
End Class
[/rbcode]
Now we've properly implemented the observer pattern. You'll notice just how powerful of a mechanism this simple paradigm is. It allows any number of observers to observe any number of objects for any number of events. This pattern is a great way for you to alert other classes when some action occurs, especially when the action is unpredictable (such as user input, data arriving from a socket or serial device, etc).
I am thinking of turning this into a full-fledged article, so feedback is welcome. Are there things you don't quite understand? Things that I missed? Things I'm... :: gasps :: ...wrong about?
No comments? I figured I'd at least get something. :-P
:(
I tried reading it three times, I get what it does and how it does it is smart, but just dont get why I would need it.
Doesn't a socket have a "dataavailable" , and nerly everything has keydown and mouse down events, what I am getting at is what would we use it for which RB cannot handle so nicely already.
TA
Damon
The observer pattern is very helpful when you want to define interactions between multiple loosly related classes.
Let's say you have three windows -- one for showing the weather, one for showing the time and one for showing the barometer. And you've only got one socket who is responsible for getting all three of these items of information.
The Observer pattern works better than relying on the DataAvailable event because the DA event gets notified when any type of data arrives, and the event can only be fired on one "owner" window. However, you have three windows that all share the same socket, so events just aren't that feasible. So instead, you use the observer pattern -- now the socket knows that whenever it gets weather data, it has to notify the weather observers. And so on for the other packet types.
Think of the observer pattern as events on steroids. They both solve the same problem of how to alert another class that something interesting has happened. However, with the OP you can notify multiple interested parties that may or may not be related in any way.
.Net's implementation of Delegation and Event handling is giving you Observer :)
mmm gotta love Observer, specially when using Strategy Patterns (MVC)
Pffft, but no one cares about .NET. ;-) Seriously though -- I find .NET's implementation of events to be very cumbersome compared to REALbasic. You have to jump thru a lot of hoops in C# to declare and use events, but in RB, it's damn simple.
Why do you have to get so damn defensive all the time? :) I was simply pointing out something that I like and you rip it to shreds...
me.Thinks() :-P
Fortuitous timing for me ...
I'd decided to use this weekend to kick-start my trying out REALBasic, from a Java background. Working with JavaBeans in particular, I kinda got used to MVC (Observer) type thinking ... and was wondering whether I'd have to kludge up something myself, or whether it wasn't REALBasic idiomatic.
Thanks,
- CA205
LoL@Jake -- chill bro, I was giving you a hard time. You pimp .NET like I pimp REALbasic. :-)
@CA205 -- Glad you found my little blurb helpful! REALbasic can handle observer easily (as you can see), but a lot of people prefer to just stick with the regular event-driven approach as well. Between the two paradigms (even with their similarities) you should be good to go.
I THINK I can see the reason for that too: the Observer Pattern generates its real advantage over "regular event-driven" [to call it that] when there are multiple Observers. However, this situation doesn't typically arise in the GUI side - it's more in the underlying business logic.
Caveat: New to REALBasic, and while I'd like to think I'm pretty good with Java I'm NOT a language design expert. So for what it's worth ...
So comparing, for instance, the RB's PushButton Control with Java's JButton [1], the big difference I note is that a given PushButton can [as far as I can tell] only be equipped with a single Action Event observer, whereas JButton can have multiple ActionListeners ("listener" is Java terminology for "observer"). Or to put it another way: in Java the controls come with broadcast support, while in RB the user is expected to handle broadcasting.
To see this, imagine the following UI: push button B inside a window W, with a label L showing the number of times that the button was pushed, and a picture P that was alternately shown or hidden with each press.
1. In RB, this would be done by writing code in the B's Action() Event Sub, which would increment the count in L and showing/hiding the picture in P. This code might be broken up into two Subs, IncrementCountInL and ShowHidePictureP, residing as methods in window W.
2. In Java, you could do it this way, BUT you could also choose to do it by writing an ActionListener IncrementCountInLListener, and another one ShowHidePicturePListener.
Thus, in this example, the button-push action from B needs to be broadcast to L and P. In Java, this is done by B using methods inherited by JButton. In RB, this has to be done by code written in W.
My personal preference is for approach (2), for i) Its distinct conceptual trails from B -> L and from B -> P, rather than intermixed B -> W -> P:L of (1), and ii) So that I have a separate class[es] encapsulating the way my program reacts to button press B. HOWEVER, this comes at a cost:
- Broadcast support built into every control (though I understand that this is designed for speed).
- Clutter in coding up all those listeners as additional classes.
- And just how often do I want to do this kind of thing anyway?
The third of these points is the crucial one. I would imagine that a given control would [typically] do just one thing conceptually - it may have multiple outcomes, but one single causal chain. So for controls there is a fair amount of sense in just having a single observer, and for that observer to be the enclosing window. Which is what RB does.
To put it another way - separate class[es] for "react to button push" are conceptually elegant, but can lead to an awful amount of code clutter to define and maintain these new classes. I suspect that this is the reasoning that lead to Java incorporating "anonymous listeners" and "inner classes" - ways of saying "Yeah, in theory there's a new class here, but in practice it's only this tiny block of code and we'll whack it in here with the enclosing window."
However, the Observer Pattern really comes into its own when multiple controls all potentially modify a single object, and thus have to be kept in synch. Take the GUI example in [2], which takes values "X" and "Y" and returns "X+Y", where each of "X" and "Y" can be modified by text entry fields OR by slider bars, raising a synchronisation issue. This can be done in two ways:
1. When the text entry field is modified, tell the slider too, and vice versa. (This gets really ugly as more controls are added.)
2. Use the Observer pattern. The "X" value is the Observable (Model), and anything that uses/modifies "X" is an Observer (View/Controller).
[1] http://java.sun.com/docs/books/tutorial/uiswing/components/button.html#abstractbutton
[2] http://www.jot.fm/issues/issue_2002_09/column6/
(Hmm, that was considerably longer than intended ... oh well.)
- CA205.
@CA205 -- excellent description! And you are correct with your information about REALbasic -- this sort of thing is normally done via events, but there are certain times when events really just need to broadcast the information to any listeners (such as your second example points out).
I think it would be good to have this extended to situations where the Observable is a collection of some kind. The basic concept centres on the Notify method, which for a collection would look something like
Function Notify( fromWho as IObserveableCollection, eventName as String, key As Variant ) as Boolean
(Excuse my poor HTML.)
So for example, if you had an IObserveableCollection implementation called GreenBottlesOnWall, then it could Notify IObserverOfCollection instances of "Accidentally Fall" events for different bottles being held (10, 9, 8, 7, ... or 3, 6, 2, 8, ...).
I'm thinking key As Variant in order to tie to the Dictionary class supplied by RB, though a particular IObserveable implementation could [obviously] use whatever internal store it liked.
What stumped me was whether and how this could be done cleanly. I spatchcocked one together through an IObserveableCollection - IObserverOfCollection pair, with ObserverList split into an ObservedEvent class with ObserveableSupport and ObserveableCollectionSupport subclasses. Not particularly happy with this ... can it be done by method overloading of just the original IObserveable - IObserver pair?
Yes, REALbasic allows method overloading so long as the method's signatures differ (by more than just the return type). Since the methods you want to add will have a different parameter signature, the methods can be overridden.
Keep in mind though that any implementor of an interface must implement all the methods of the interface (just like in Java), so even Observerables that don't have any collection support must now support a collection method on them as well. This may be acceptable in some circumstances, but it may seem kind of hackish in others. So I would suggest sticking with separate interfaces for the collection support so that an object has the chance to be the most specific type. Multiple interface support for objects means that an object can be both observeable as a single entity and/or a collection, so you don't lose functionality, but you gain code elegance.
"Spatchcocked" is my new favorite word for the week. :-)
Oh yeah ... one other thing that may be worth noting about the Observer Pattern - I think it makes Undo support a LOT easier to implement.
Consider: If all the changes are being performed by calling the Observeable (which then broadcasts them out through Notify), then that's the logical place to be generating an Undo stack.
So take Observers o1, o2, o3 of an Observable O. If something changes O, O stores the change onto its undo stack Z, and broadcasts the change to o1, o2 and o3. Conversely, if the undo is invoked, O just pops off the stack Z and broadcasts the change as before.
Again, this really comes up in the multiple Controls acting on a single Model situation. I think (though I've never actually had to implement this!) pretty straightforward to implement a Undo handler as a View-Controller (Views changes and pushes them onto stack, Controls undo by popping the stack). By comparison, putting the Undo handling among the multiple Controls is rather painful to contemplate.
I'd forgotten about the aspect that a given object might selectively choose to be an IObserveable and/or an IObserveableCollection, and vice versa for IObserver / ICollectionObserver .
We use the observer pattern all over internally for things, and undo stacks was one of the first things implemented. You're correct, if you ever plan on implementing Undo, the observer pattern is really a handy way to go. Another very helpful design when doing undo is the "action" pattern. I think I'll describe that one in another post though, since it's a fairly easy, but long discussion.
Tried out IObserver-IObserveable / IObserverOfCollection-IObserveableCollection during the week on a small project. What I rapidly found is that I had to change the interface to
Function Notify( fromWho As IObserveable, eventName As String, oldValue As Variant, newValue As Variant) as Boolean
The reason was that I was working with Observer instances that, in order to react to Notify, needed to know the old and new values, so it wasn't just enough to interrogate the Observable for its new value.
Of course, I might be breaking the design here ... got used to the java.beans packages, with the PropertyChangeListener class (http://java.sun.com/j2se/1.4.2/docs/api/java/beans/PropertyChangeListener.html).
Java bundles up all the parameters to Notify (propertyChange()) into a PropertyChangeEvent object ... I can think of advantages and disadvantages to this, erring to NOT doing so for RB given its Variant type.
Supplying oldValue and newValue makes Undo implementation cleaner too [I think], by making the Undo Manager an IObserver to all IObserveables that can be undone, and storing a stack of (fromWho, eventName, oldValue, newValue) tuplets.
I've implemented the Observer pattern using a module rather than an helper class as Aaron has shown us. My idea was to provide a way for a class to become a Subject, with minimal impact on the class's code.
So I have a mObserver module with :
Sub add[event]Observer(Extends subject As Object, observer As ci[event]Observer)
Sub removeObserver(Extends subject As Object, observer As Object)
Sub on[Event](Extends subject As Object)
A subject only has to signal its events : e.g me.on[event]
An Observer does : interestingObject.add[event]Observer(me)
and then : interestingObject.removeObserver(me)
[Event] is replaced by the name of supported events such as 'onChange', 'onError' ... The idea was to be able to use arguments when notifying an event : the interface allows the compiler to check that the observer has the relevant method implemented.
e.g if I want to pass the new value in the onChange event, then ciOnChangeObserver would have :
sub onChange(newValue As Variant)
I've now come to question that, as it seems that arguments are of little practical use.
I'm happy with the module approach, and with the Observer pattern in general. I've found that it allows me to dramatically reduce the amount of 'glue-code' that I used to have in my projects.
Aaron, thank you for sharing your ideas here. I'll be back regularly.
The example of where I found a need for oldValue and newValue is as follows:
I have a list of items I_1, I_2, ... , I_k, ... that will be assigned to persons Anna, Bradley, Clara, David and Elliot, and for each of these persons I want to see the items assigned to them.
My preferred user interface is through two Listbox'es : Listbox1 with two columns, where the items are in the left column and the user enters/selects the assigned name for each, and second Listbox2 which displays the items for each person (one person per row).
So visually, if I have Listbox1
I_1 Anna
I_2 Elliott
I_3 Anna
I_4 David
I_5 Elliott
I_6 Anna
then I'll have Listbox2 as
Anna I_1, I_3, I_6
Bradley
Clara
David I_4
Elliott I_2, I_5
It seemed to me that the appropriate data model would be a sequence of tuples (Item, Person), where each Person would be initialised as blank, and could be edited to suit. So, for instance, the user (in the above) would edit Listbox1 and change I_6 to Elliott, and then Listbox2 would be updated (through the Observer pattern) to I_2, I_5 and I_6 for Elliott.
If I make these tuples an ObserveableCollection, then with the original interface, I'd know that item I_6 had changed. However, without knowing the old values Anna and Elliott, I don't see how I can know that just those rows in Listbox2 had been dirtied, and hence would have had to redraw the entire Listbox2 instead of just the rows for Anna and Elliott.
Or maybe I'm not thinking laterally enough or something ...
BTW I like the Extends keyword.
Thanks - I'm finding this very useful.
- CA205.
Great Article Aaron! Thanks.
I've implemented this pattern as you described. But I ran into a snag. The observers may not (should not need to?) know about the detail of the observable sending notifications. So shouldn't the actual 'message' be part of the notification?
I'm using this specifcally with async task, such as sockets. The socket being the observable, I have a statictext that is interested in the name of the current file being uploaded. I have a progressbar observer that is interested in the bytes sent. So I implemented 'status' and 'progress' as eventnames.
How should the Notifier pass this information along? The progressbar wants a double, the statictext a string.
Would the 'correct' way to handle this be to add a 'eventData as Variant' to the Notify call? Or perhaps use a Notification helper class to transport eventData? Or should one consider implementing Observable interfaces that are more specific to the task?
Thanks again,
Juergen
Usually, the way that I write my observed classes is in such a way that the observer is able to query the observed for that sort of information. So in your example, the StaticText would be notified of a file name change event, and then it would query the observed object (which is passed into the notification event) for whatever information is needed. I tend to do this because I've found that you can never pass in *enough* information -- you'll always run into cases where you need more.
That being said, there's nothing wrong with modifying the pattern to have it pass event data in as a variant along with the event string. That's certain a decent way of doing things and should work well in many instances.
Ok, so initially I added an 'accessor' to the IObservable interface that would allow retrieval of named parameters. But I found myself tracking all those parameters in the implementing classes inside a dictionary so that I could refernce them by name. The result of this then was to just pass a Dictionary as eventData, because it can transport virtually anything.
So when an Observer receives a notification for a given event, then it can query the dictionary for expected named parameters without guarantee that they'll be there and act accordingly. Use of the dictionary.Lookup method with default values completes the cat's meow.
Sound alright?
Sounds great!
For what it's worth (and possibly stating the very very obvious) ...
I also like the idea of passing eventData As Dictionary, since it allows me to wrap up the IObserverOfCollection-IObserveableCollection pair too. Now I'm just using a single pair of interfaces: IObserver-IObserveable (as before), where NotifyObservers calls If observer.Notify( mFromWho, eventData ) = True Then and keys in eventData handle "name", "index" ... or whatever else I want at broadcast time.