In Defense of Observers

Andy on Apr 26th 2007

Recently Brent Simmons posted his thoughts about large cocoa projects, which elicited a lot of responses within the Mac programmer community about what makes code easier to “research.” There’s a lot of good stuff there, but I wanted to focus on one facet of the discussion that was brought up, namely NSNotificationCenter.

First, anyone who has read the Design Patterns book knows that NSNotificationCenter is the observer pattern. It is useful for decoupling objects, in which is a good thing, because it makes classes more reusable (because they have fewer dependencies) and more maintainable, because, if done correctly, it insulates changes in one class from another class. These are all good things, and observers are good, and you should use them.

The problem comes up with Apple’s implementation of NSNotificationCenter, and I’ve often wondered why they chose the implementation they did. There are a few problems with it:

  1. As noted by Michael Tsai, NSNotificationCenter is a singleton, and thus essentially is one big honkin’ global. Globals are bad ™.
  2. NSNotificationCenter allows a many-to-many relationship between observers and their subjects. That is, many different subjects can send the same notification, and several observers will listen for the notification, regardless of the sender.

    This breaks the observer pattern, which was intended as a one-to-many relationship, because it breaks the idea that the observer observes the subject. Instead it produces the idea that the observer observes the notification, which is wrong. The notification is simply a convenient way to pass information between classes, it is not really a part of the relationship between the subject and the observer.

  3. The syntax of using NSNotificationCenter puts the notification center as the receiving object, and thus puts the focus on the notification center, instead of focusing on the relationship between the subject and its observer.

These problems are compounded by the fact that just about all sample code that I’ve seen, from Apple and others, use NSNotificationCenter in the many-to-many relationship, instead of a one-to-many relationship.

Of course Cocoa uses another design pattern that can be used as a stop-gap for the observer pattern: delegates. Delegates define a simple one-to-one relationship between the subject and its delegate. It has the benefit of being easy to implement and clarifying the relationship between the subject and delegate. The problem is, it’s not appropriate for the observer pattern, for a couple of reasons:

  1. As the name implies, a delegate is delegated tasks or decisions. That is, a subject is dependent on the decisions a delegate makes, and will change behavior depending on if, and which, delegate is attached. This is the opposite of an observer pattern. The subject does not care who is listening, or if anyone is listening at all. The observer, however, will often change behavior or take action, depending on what the subject does. In other words, the dependency is modeled in the exact opposite direction in the delegate pattern.
  2. The delegate pattern is a one-to-one relationship, but the observer pattern is a one-to-many. It makes sense that a delegate subject would only have one delegate making decisions for it, but it doesn’t make sense that an observer subject can only have one observer listening to it.

Still, you can trivially implement a one-to-one version of the observer pattern using the same technique as implementing a delegate. You just shouldn’t call it a delegate because you’re implying the wrong direction for dependence.

All this said, there’s a much better way to implement the observer pattern, which I’ve seen in just about every other framework I’ve used. Things get a little tricky in Objective-C because the lack of multiple inheritance disallows use of mix in classes. However, it can still be done. Essentially you’d need two classes: ObserverSubject and Observer.

ObserverSubject maintains a list of Observer objects that are listening to the subject. It has hidden methods, called only by Observer, for connecting and disconnecting interested Observers, and a notify method for the actual subject to notify all listeners that an interesting event has happened.

The Observer class maintains a list of all ObserverSubjects that it is currently listening to. This is for the express purpose of automatically disconnecting from them when the Observer object is destroyed. The main method on the Observer class is called watch, and connects the Observer with the Subject. The Observer class also keeps a pointer to the actual observer, which it forwards all notifications to.

A simplified example of how these classes would be used:

@interface MySubject {
}
- (ObserverSubject*) subject;
@end

@interface MyObserver {
}
- (Observer*) observer;
@end

MySubject* mySubject = [[MySubject alloc] init];
MyObserver* myObserver = [[MyObserver alloc] init];

[[myObserver observer] watch:[mySubject subject]];

In this design, the one-to-many relationship is enforced, and the syntax puts the focus on the relationship between the subject and its observer. Also note the lack of globals.

In conclusion, observers are a good thing, and you shouldn’t write them off just because Apple did a shoddy job of implementing them. Modeling simple one-to-one observers is trivial to implement, and modeling a true one-to-many observer pattern isn’t all that difficult either.

Filed in Programming | 16 responses so far

16 Responses to “In Defense of Observers”

  1. /dev/klog » Archive » NSNotificationCenter isn’t a singleton Apr 26th 2007 at 02:17 pm 1

    […] This was posted by Andy Finnell echoing Michael Tsai. […]

  2. Jamie Apr 27th 2007 at 01:43 am 2

    Andy,

    I think you make great points about the differences between the delegate and the observer patterns which were missed in the original post, however I think that your proposed Observer / Subject classes aren’t so useful in objective-c for the reasons you have already specified. As you say this is due to the lack of multiple-inheritence in the language but your method means inheritting from the classes directly which is also not always ideal. Would be nice if there was some more felxible manner to implement this.

    Jamie

  3. Diederik Hoogenboom Apr 27th 2007 at 02:23 am 3

    Hi Andy, nice post.

    I am wordering how KVO will fit into this? KVO is basically a one-to-many observing relationship. With KVO, the observer has to know about the object, which is not the case with NSNotificationCenter (violating the observer pattern). The observed object also knows about who is observing.

    Diederik

  4. patrick Apr 27th 2007 at 03:35 am 4

    I don’t agree. NSNotificationCenter doesn’t implement the observer design pattern in the strict GOF sense (Notification is more of an amalgamation of Observer and Mediator). Its most important feature is that it _decouples_ the ‘observer’ from the ‘observed’. As a result, the ‘observer’ doesn’t need a reference to the ‘observed’ object (in fact, it doesn’t even have to exist yet). This is a great feature in its own right, and something that was (has been?) missing in Java (which has observers proper) for a long time.

    That said, you can use the notification center to listen to changes to a specific object too, if you want, and create a tighter coupling between broadcasters and listeners.

    If I were to take issue with the implementation of ‘observers’ in OS X, it would be with the KVO mechanism. It is really strange that it forces the listener to implement a specific method through which all change callbacks are funneled, and that it doesn’t offer the flexibility of registering a callback selector, as you would expect.

    And why the dogmatic stance against singletons? Just like any other design pattern they have pro’s and cons. In the case of NSNotificationCenter they seem to be the right solution. I hope you won’t outlaw NSApplication next ;-)

  5. Anonymous Coward Apr 27th 2007 at 03:36 am 5

    So at first it’s “anybody who’s read ‘the book’ knows that NSNotificationCenter is an observer pattern”. Then you describe how it ‘breaks’ the dear observer pattern.

    Hello ? McFly ?

  6. Shawn Apr 27th 2007 at 09:34 am 6

    Nothing forces you to use the default notification center. You can create your own that are owned/scoped by specific classes/objects in your application. I do this all the time.

  7. Andy Apr 27th 2007 at 11:26 am 7

    @Jamie: Would be nice if there was some more felxible manner to implement this.

    I thought I outlined a nice way to implement it at the end of the post. :-) You simply aggregate the Observer or Subject object, which contains a pointer back to the real observer or subject. In Objective-C the Observer (or Subject) can simply forward the message invocations to the real object. There is a level indirection there, but its still quite usable. In fact I’ve seen this design used in C++ where there is multiple inheritance.

    @Diederik: Unfortunately, I haven’t really used KVO, so I can’t really comment on them. I know some others have expressed displeasure with how they’re implemented.

    @Patrick: Agreed, NSNotificationCenter doesn’t implement the observer pattern, that was my point. However, people (including from Apple) are using it in that manner. I agree, the way it is architected is useful, just not as an observer pattern.

    Also, I’m not against singletons. I like them, and use them. As you say, there are times to use them, and times when they’re not appropriate. I’m saying when you want an observer pattern, they’re not appropriate.

    @Anonymous: My point was people were using the NSNotificationCenter as if it were the observer pattern, and my point was it isn’t.

    @Shawn: Yes, that is true. But I still think NSNotificationCenter shouldn’t be used in place of the observer pattern, when that’s appropriate. NSNotificationCenter still represents a many-to-many relationship, even when you use multiple of them.

  8. patrick Apr 27th 2007 at 01:15 pm 8

    @Andy: Definitely check out KVO. The implementation (both under the hood an the API) may be a little bit strange, but that doesn’t detract from the fact that it works. It’s Cocoa’s Observer, and I find it really useful.

    The thing that surprised me in this week’s ‘large projects’ discussion was how a number of high profile (== blogging) developers criticized some great Cocoa features. Notifications suddenly confuse the flow of control, KVO is ‘only for preferences’, bindings are ‘hidden in the nib’ and are to be avoided. Oh my… Let’s all agree that these are wonderful technologies that make our lives so much easier. And let’s remind ourselves that the _only_ effective way to remember how a program works is to read the _documentation you wrote when you created the code_… If you were lazy, don’t take it out on the framework, it can’t help it.

    Which brings us to the sorry state of HeaderDoc ;-\

  9. Stephane Apr 27th 2007 at 03:49 pm 9

    I don’t see the point with the one-to-many thing. The purpose of a notification is not to care about the sender but about the message. When you’re watching TV news, it’s not the anchorman that matters but the news itself.

    For me, NS[Distributed]NotificationCenter just works.

  10. Nathan Day Apr 27th 2007 at 06:15 pm 10

    You can get one-to-many relationship when an notification observer specifies which object it wants to receive notifications from. The great thing about Apples Notification Centre is it can function as a one-to-many and a many-to-many and individual notifications can act as both ways, letting the observer decided. You seem to be a little dogmatic about design patterns, the notifications are there own design pattern that can do the observer pattern, and you criticism seems to they don’t police the observer pattern for your.

  11. Anoymous Coward Apr 28th 2007 at 06:04 am 11

    >@Anonymous: My point was people were using the
    > NSNotificationCenter as if it were the observer
    > pattern, and my point was it isn’t.

    I find it curious that you’re argument now involves the supposed incompetence of some nameless people. (Who are they ?) Would it not have been more honest if you had written:

    “I read the Design Patterns book and thought NSNotificationCenter is exactly the observer pattern, but then I noticed…”

    My response would be nicer, if you hadn’t written in this annoying preaching style. This is “good” this is “bad”. Apple’s work is “shoddy”. You’re doing a lot of posturing and preaching, but you have very little to back it up.

  12. igerard Apr 28th 2007 at 03:58 pm 12

    Programming is not religious.

    NSNotificationCenter allow to implement observable/observer relationship/behavior in a very easy way.

    If you want to implement this pattern in a one to many relationship way it is easy with NSArray, selector, target, and category on NSObject to get code usable from everywhere in your class tree, not as clean as protocol but it does work.

    You can even use NSInvocation which is an interesting object allowing more complexe signature for message targeted to the observer.

    To make short, NSNotificationCenter is a compromise to get something very usable, genereic… I suspect that NSNotificationCenter use heavily Hash table, hence in some circumstance you can get poor performance, and then it is a good idea to make specialized instance of NSNotificationCenter.

  13. Brent Apr 30th 2007 at 07:23 pm 13

    Andy,

    Sorry to be blatantly contradictory, but you are free to use NSNotificationCenter (either the default, or one of your own creation) in a one-to-many manner if you desire. you simply provide the object which you are observing. Optionally, you can omit the notification name and receive all notifications regarding the observed object. From the docs:

    notificationName
    The name of the notification for which to register the observer; that is, only notifications with this name are delivered to the observer. When nil, the notification center doesn’t use a notification’s name to decide whether to deliver it to the observer.

    notificationSender
    The object whose notifications the observer wants to receive; that is, only notifications sent by this sender are delivered to the observer. When nil, the notification center doesn’t use a notification’s sender to decide whether to deliver it to the observer.

    In any case, regardless of the actual facts, but based on the ones you present, your argument in and of itself is, as pointed out by others, fundamentally flawed. You are trying to say that the designers of Foundation (and it wasn’t Apple, but NeXT) intended to implement a pattern and failed, whereas you have no way of knowing what they intended. You are merely assuming.

  14. Brent Apr 30th 2007 at 07:32 pm 14

    About global variables: they are not universally bad. All C functions (like main() or NSSelectorFromString()) are in the global namespace. NSApp is in the global namespace. All classes are in the global namespace. Singletons are not bad; certainly not because they are global, though in Cocoa they usually aren’t: the sharedNotificationCenter, anymore than the sharedDocumentController, is *NOT* a global; you have to ask for it from the class object.

    Globally available symbols are essential for software to work properly; the alternative to global visibility would be long chains of references, which would lead to the same thing. Every object graph has a root; relative to every other object in the graph, that object is “global”. And sometimes, you have to talk to the root object.

    Open up XCode’s debugger and click on the globals disclosure triangle and check out the tremendously large number of global variables, without which, a lot of code would be much more obfuscated and difficult to use.

    The problem with global variables goes back to C structures being shared around by everybody. Code all over an application could alter their contents, creating unmanageable complexity. Encapsulation solved that problem; globally available objects are not the same thing as global variables.

  15. Andy Apr 30th 2007 at 08:57 pm 15

    @patrick: Thanks for the info about KVO. I’d love to take it for a spin as soon as I have a project that allows me to do that.

    Also, I don’t think bloggers were too rough on the Cocoa features. Brent and others pointed out some gotchas and limitations of the technologies, but I don’t think any of them meant: “these are bad technologies.” In fact, I remember some praise of bindings, and rightfully so.

    @Stephane: The pattern you describe with the anchorman and the news is the Moderator pattern, not the Observer pattern. If that’s your model, then (I think) you would be correct to use NSNotificationCenter. In the Observer pattern, the observer actually cares about one specific subject (the person actually making the news in your example, as opposed to the anchorperson). My point was, in that model, NSNotificationCenter is not appropriate. Also note that the news example is a many-to-many relationship. Many people are making the news, and many people are listening to it.

    @Nathan: I will admit I can be a bit dogmatic about design patterns, and anal about coding standards. You are correct that the notifications are their own design pattern. My point is that they are not the Observer pattern, completely, although they get used in that manner. I was trying to point out a better way (a implementation that was only the Observer pattern).

    Although I don’t expect classes to police for incorrect use, it would be nice if they didn’t encourage it.

    @Anonymous: I never said anyone was incompetent, nor was that my intent. My argument was simply: “there’s a better way to do this.”

    I’m sorry that you dislike my writing style. I fully confess that I am an engineer and not a professional writer. I’m sorry that the fact that I identified things as “good” or “bad” annoyed you, but that is the way of the world. Some things really are “good” while others are “bad.”

    As you might have noted, this is my personal blog, and the implicit implication is that everything here is my personal opinion. You are free to accept or reject my opinions at your whim, and it will not offend me in the least.

    @igerard: Sorry to chase a rabbit here, but I’d like to have a minute with your initial comment: “Programming is not religious.”

    People say this, and mean it, but can never do it. Programming is religious, and each person has their own little cult. Whether it is over whether programming is an art or science, or if inlining is really worth it, or if source control should be used, or the indention style that should be used. Each programmer has their own idiosyncrasies that they cling to, despite the lack of evidence, or even evidence to the contrary, that they are true.

    Alright, rabbit chased.

    Although NSNotificationCenter can be used to implement a one-to-many relationship, it is often not used that way (at least in the code I’ve seen), and it does not enforce this. Also, the syntax of its use (like I mentioned in the post) does not lend itself to the relationship of the objects.

    @Brent: Thanks for pointing to the docs, but I already knew that (and mentioned it briefly in my post), and I believe you missed my point. As I stated in the post, although NSNotificationCenter will allow you to establish a one-to-many relationship, it allows many-to-many, and the common use appears to be many-to-many, even when the real relationship is one-to-many.

    I will fully admit that I don’t know what the original designers intended. However, I would like to point out that sword cuts both ways: unless you have information that you didn’t mention, neither do you.

    I also don’t think the original designers intended a pure Observer pattern. My point was that although it is not an Observer pattern, it is used in that function, and Apple has not provided an appropriate one-to-many Observer pattern in Cocoa (unless KVO is it).

    As far as globals goes, you took my one comment and blew it _way_ out of proportion. I admit that was probably at least partially my fault because of my attempt at humor (note the “trademark” sign in my statement). I never said that all globals were bad, and should never be used. I, occasionally, will use singletons and local static variables. I even clarified this in one of my earlier comments. However, my point was, in a one-to-many Observer relationship, there is no need to have a global.

    To your comment that singletons aren’t globals, I will have to disagree. You are correct that they will often encapsulate their member data, which makes them better that a global C struct. However, singletons share the same global access from any part of the code that proper globals do. This means they are open for being used from anywhere, which can produce much tighter coupling than necessary.

  16. Frank May 1st 2007 at 08:54 am 16

    Why don’t you use a protocol to implement the observer? That way you don’t need to inherit from it, and you can “mix” it in with existing classes…

Trackback URI | Comments RSS

Leave a Reply

Bad Behavior has blocked 408 access attempts in the last 7 days.