Design patterns are fundamental part of the glue which sticks together the 20% percent of the design which makes 80% of the work. They’re the frontier line between Architects and Designers. They’re a common work area. But not for everyone is obvious that patterns describe a general solution for a given scenario. General solution is not intended to be the solution for your project. It’s just a general solution. It might work as is or it might not.
Let’s consider the Observer pattern. In articles and commercial products is suggested to use the pattern in real world scenarios as is. Implementing the patterns as is involves defining a subject interface, a concrete subject, an observer and a concrete observer. You should not be constraint by the conventions of a particular design pattern. The pattern offers you a solution for implementing notifications/actions based on observing changes of states. The pattern should be evaluated before implementing it. Don’t create classes or interfaces just because the pattern commands you so. Start with the functional requirements and then the non-functional requirements in a customer first style.
If you are a C# developer willing to implement the Observer pattern bear in mind that the pattern is not restrained for UI scenarios. The MVVM pattern and the C# ObservableCollection implementation make people think so, but the pattern goes far beyond UI scenarios. So, don’t get confused by commercial products implementing anti-patterns or by vendor specific built-in solutions that are intended for a subset of scenarios solved by the pattern.
First off, if you don’t need all the classes suggested by the pattern, don’t implement them. Then take advantage of your development platform without adding exotic elements in the process. The best implementation of the Observer pattern I have found so far uses events and delegates to decouple the Observer of the Subject. So you don’t have to keep track of the concrete Observers within the concrete Subject. In my opinion, holding a reference of the concrete observers within the concrete subject breaks encapsulation. I think the same about injecting a concrete observer as a dependency to the concrete subject.
I like the mentioned implementation because events and delegates follow the Hollywood principle “don’t call us, we’ll call you”, so you don’t need to explicitly call code on concrete observers and favor extensibility (see my previous post: Designing your API for extensibility), plus you can go further and add a mediator object to plug the subject with the observer. You could decouple two Facades working on common data by defining a subject interface exposing an event (similar to the INotifyPropertyChanged), then implement a concrete subject and hook it up with a concrete observer using a mediator.
If you haven’t noticed that the title was inspired in the following statement by Steve McConnell in his book Code Complete, You should grab one copy quickly, I read it for the first time several years ago and trust me, it will make you a better Designer:
Programmers who program “in” a language limit their thoughts to constructs that the language directly supports. If the language tools are primitive, the programmer’s thoughts are also primitive.
Javier Andrés Cáceres AlvisMicrosoft Most Valuable Professional – MVP Intel Black Belt Software Developer