Click here to Skip to main content
Click here to Skip to main content

Implementing the Observer Pattern

, 5 Feb 2008
Rate this:
Please Sign up or sign in to vote.
An article that discusses how to implement the observer pattern

Introduction

While I was developing a new web application in our company, I found that every entity in the system had some shared fields that held data about when and who saved that entity into the system. Basically, those fields were CreationDate, CreatedBy, LastModificationDate, LastModificationBy and EntityId for sure. There are multiple approaches to solve this situation:

  1. In every user control, include these fields and reflect data to them directly. However, this would force you to write more duplicated code and would make update and maintenance more complicated and error-frequent processes. Imagine that you had 10 controls; this means you you'd need to do 10 updates if any update were needed in the entity details.
  2. Create a user control called details and place those fields in it, accessing those fields directly from each entity screen. Although this would ease maintenance and updates, this approach has a disadvantage in that those controls would now be tightly coupled. Applications with tightly coupled classes tend to be brittle and difficult to maintain, because changes in one class could affect all the tightly coupled classes. The problem: how can user controls -- objects -- notify other controls –- objects -- of state changes without being dependent on their classes?
  3. Use the observer pattern and create loosely coupled controls to communicate between each other without depending on their classes.

In this article, I will show how to build a simple user control that implements the observer pattern to handle updates and pass notifications around, which is done in order to update a set of objects when some important event has occurred.

Background

The observer pattern is categorized under Behavioral Patterns. Behavioral Patterns are those patterns which are concerned with algorithms and the assignment of responsibilities between objects. Behavioral patterns describe not just patterns of objects or classes, but also the patterns of communication between them.

So, What is the Observer Pattern?

The observer design pattern should, “Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.”

What is the Subject? What is the Observer?

Subject: the object which will frequently change its state and upon which other objects depend.

Observer: the object which depends on a subject and updates according to its subject's state.

Here’s how it works: an observer signs up to receive notifications of changes to the subject.

A second observer can register itself, too. In fact, a subject may have any number of dependent observers. Observers are not aware of the presence of each other.

When a certain event occurs, all observers are notified.

An observer can unregister itself from a subject so that it will never receive notifications from the subject.

With this generic way of communicating between the subject and observers, collaborations can be built dynamically instead of statically. The code is now much more separate, and thus easier to maintain and reuse. There is no direct dependency between subject class and observer class.

Using the Code

In our example, Address_UC is a ConcreteSubject and RecordDetails_UC is one of its ConcreteObservers. So, when the domain object associated with the Address_UC class has changed, the RecordDetails_UC class will be notified and will handle this event in a proper way. I will show how to explicitly implement the observer pattern another time by using delegates and events.

Implementing Subject Class

You can implement the Subject class as a super class or abstract class. However, due to the limitations in some languages like C# and VB.NET, that class can inherit only once. This will cause a problem because most domain objects are inherits from domain objects. So, our subject class will be implemented using an interface. Remember that class can implement many interfaces.

public interface ISubject
    {
        List<IObserver> ObserversList {get;}
        void AttachObserver(IObserver observer);
        void DeAttachObserver(IObserver observer);
        void NotifyObservers();
    } 

Implementing the Observer Class

public interface IObserver
    {
        void Updateobject(ISubject subject);
    }

The observer class is very simple and contains a method that allows subjects to notify it. All we need to know is how to implement ISubject methods in our ConcreteSubject Address_UC. It's as simple as this:

#region ISubject Members
        public List<ObserverTutorial.App_Code.IObserver> ObserversList
        {
            get { return this.m_ObserversList; }
        }

        public void AttachObserver(ObserverTutorial.App_Code.IObserver observer)
        {
            this.ObserversList.Add(observer);
        }

        public void DeAttachObserver(ObserverTutorial.App_Code.IObserver observer)
        {
            this.ObserversList.Remove(observer);
        }

        public void NotifyObservers()
        {
            foreach (App_Code.IObserver observer in this.ObserversList )
            {
                observer.Updateobject(this);
            }
        }
#endregion

Note that the NotifyObservers method will be called form another method in Address_UC when a certain event occurs, something like after a user saves domain object data:

protected void btnOk_Click(object sender, EventArgs e)
        {
            bool result = SaveEntityData();
            
            /// After Subject object data is saved in a state notify observers
            if (result)
            { 
            this.NotifyObservers();
            }
        }

In the ConcreteObserver RecordDetails_UC, the implementation of the IObserver lonely method Updateobject allows Address_UC to notify RecordDetails_UC that it has changed. It is passing itself as a parameter so that RecordDetails_UC can update its state, too, in a proper way. Firstly, however, RecordDetails_UC needs to register itself with Address_UC:

ISubject Subject = this.Parent as ISubject;
            if (Subject != null)
            {
                Subject.AttachObserver(this);
            }

Points of Interest

The Microsoft .NET Framework defines the notion of delegates and events to accomplish the observer role. Therefore you would rarely implement the observer pattern explicitly in .NET, but should use delegates and events instead. I attached an implementation of this sample using delegates and events, too.

History

  • 5 February, 2008 -- Original version posted

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Huthaifa Afanah
Web Developer NTS
Palestinian Territory (Occupied) Palestinian Territory (Occupied)
Huthaifa lives happily in Jerusalem and enjoys his time developing web applications and learning new stuff.

Comments and Discussions

 
GeneralFinally, a simple, straightforward explanation. PinmemberPatrick Sears5-Feb-08 7:50 
GeneralRe: Finally, a simple, straightforward explanation. Pinmember leppie 5-Feb-08 8:03 
GeneralRe: Finally, a simple, straightforward explanation. PinmemberRobert Nadler5-Feb-08 8:49 
GeneralRe: Finally, a simple, straightforward explanation. PinmemberMaxGuernsey11-Feb-08 13:03 
GeneralRe: Finally, a simple, straightforward explanation. PinmemberPatrick Sears5-Feb-08 8:58 
GeneralRe: Finally, a simple, straightforward explanation. PinmemberHuthaifa Afanah5-Feb-08 19:44 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web03 | 2.8.140821.2 | Last Updated 5 Feb 2008
Article Copyright 2008 by Huthaifa Afanah
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid