I’m not talking about the design model here, but the java.util class and interface. From a development standpoint the interfaces should die a painful death and here’s why:
(1) It violates the rule of discovery–that a newbie to the code should be able to discover easily what is going on. If you’re maintaining some code and you need to change the object you’re passing to notifyObservers, because the object being passed is a generic Object, you have no good way to discover which Observers would be affected. Two different Observers will have the exact same interface–but one may be affected while the other is not. You have no good way to figure out through simple search which observers are observing which observables.
(2) Like the dreaded ‘GOTO’, it makes it easy to write spaghetti code. One of the bad habits in Java is for people to create inline anonymous classes to handle events and state changes–and while this makes the original author’s life easy, it makes figuring out what little ‘classlet’ or snippet of code functionally belongs to another chunk of code. You may have a toolbar with five different buttons which seem functionally related–but the code which processes the contents may be scattered throughout your code.
This ability to create little anonymous inline classlets of functionality is Java’s equivalent to the GOTO: easily abused, it creates spaghetti code real quick. And observers simply encourage this practice.
(3) It potentially introduces event order dependencies. While an observer should preferably be used to update an unrelated element when a state changes–such as highlighting the ‘window dirty’ icon in a document window, in many cases I’ve encountered the observer object is used as a sort of “cross-cutting” functionality enabler–with cross-cut functionality added in a way which creates hard to understand dependencies.
I’ve got one class here where the notification creates a state change which later code in the observable depends upon. In other words, the observable depends upon the state of the observer to change before the observable can continue: fail to register the observer, and the observable fails.
It’s the dreaded GOTO all over again, except worse: it’s data driven GOTOs…