Observer pattern

From Wikipedia, the free encyclopedia

(Redirected from Event listener)
Jump to: navigation, search

The observer pattern (sometimes known as publish/subscribe) is a design pattern used in computer programming to observe the state of an object in a program. It is related to the principle of implicit invocation.

This pattern is mainly used to implement a distributed event handling system. In some programming languages, the issues addressed by this pattern are handled in the native event handling syntax. This is a very interesting feature in terms of real-time deployment of applications.

Contents

The essence of this pattern is that one or more objects (called observers or listeners) are registered (or register themselves) to observe an event that may be raised by the observed object (the subject). (The object that may raise an event generally maintains a collection of the observers.)

The UML diagram below illustrates this structure:

Image:observer-pattern-uml.jpg

The participants of the pattern are detailed below. Member functions are listed with bullets.

This class provides an interface for attaching and detaching observers. Subject class also holds a private list of observers. Contains these functions:

  • Attach - Adds a new observer to the list of observers observing the subject.
  • Detach - Removes an observer from the list of observers observing the subject.
  • Notify - Notifies each observer by calling the notify() function in the observer, when a change occurs.

This class provides the state of interest to observers. It also sends a notification to all observers, by calling the Notify function in its super class (i.e, in the Subject class). Contains this function:

  • GetState - Returns the state of the subject.

This class defines an updating interface for all observers, to receive update notification from the subject. The Observer class is used as an abstract class to implement concrete observers. Contains this function:

  • Notify - An abstract function, to be overridden by concrete observers.

This class maintains a reference with the ConcreteSubject, to receive the state of the subject when a notification is received. Contains this function:

  • Notify - This is the overridden function in the concrete class. When this function is called by the subject, the ConcreteObserver calls the GetState function of the subject to update the information it has about the subject's state.

When the event is raised each observer receives a callback. This may be either a virtual function of the observer class (called 'notify()' on the diagram) or a function pointer (more generally a function object or "functor") passed as an argument to the listener registration method. The notify function may also be passed some parameters (generally information about the event that is occurring) which can be used by the observer.

Each concrete observer implements the notify function and as a consequence defines its own behavior when the notification occurs.

The typical usages of the observer pattern:

  • Listening for an external event (such as a user action). See Event-driven programming.
  • Listening for changes of the value of an object property.
  • In a mailing list, where every time an event happens (a new product, a gathering, etc.) a message is sent to the people subscribed to the list.

The observer pattern is also very often associated with the model-view-controller (MVC) paradigm. In MVC, the observer pattern is used to create a loose coupling between the model and the view. Typically, a modification in the model triggers the notification of model observers which are actually the views.

An example is Java Swing, in which the model is expected to issue change notifications to the views via the so-called PropertyChangeNotification infrastructure. Model classes are Java beans that behave as the subject, described above. View classes are associated with some visible item on the GUI and behave as the observers, described above. As the application runs, changes are made to the model. The user sees these changes because the views are updated accordingly.

/* First create two interfaces that will encapsulate the methods of a subject including:
 * ISubject --> interface for the subject
 * RegisterObserver(IObserver observer); used to register an observer to the subject's notification list
 * UnregisterObserver(IObserver observer); used to remove a registered observer from the subject's notification list
 * NotifyObservers(); used to notify the observers in the notification list of any change that occurred in the subject
 */
public interface ISubject
{
    void RegisterObserver(IObserver observer);
    void UnregisterObserver(IObserver observer);
    void NotifyObservers();
}
/* IObserver --> interface for the observer
 * Update(); called by the subject to update the observer of any change
 * The method parameters can be modified to fit certain criteria
 */
public interface IObserver
{
    void Update();
}
// Subject --> class that implements the ISubject interface.... 
using System.Collections;
 
public class Subject : ISubject
{
    //use array list implementation for collection of observers
    ArrayList observers;
 
    //decoy item to use as counter
    int counter;
 
    //constructor
    public Subject()
    {
        observers = new ArrayList();
        counter = 0;
    }
 
    public void RegisterObserver(IObserver observer)
    { 
        //if list does not contain observer, add
        if(!observers.Contains(observer))
        {
             observers.Add(observer);
        }
    }
 
    public void UnregisterObserver(IObserver observer)
    {
        //if observer is in the list, remove
        if(observers.Contains(observer))
        {
            observers.Remove(observer);   
        }
    }
 
    public void NotifyObservers() 
    {
        //call update method for every observer
        foreach(IObserver observer in observers)
        {
            observer.Update();
        }
    }
 
    //use function to illustrate observer function
    //the subject will notify only when the counter value is divisible by 5
    public void Operate()
    {
        for(counter = 0; counter < 26; counter++)
        {
            if(counter % 5 == 0)
            {
                NotifyObservers();
            }
        }
    }
}
// Observer --> Implements the IObserver
public class Observer :IObserver
{
    //this will count the times the subject changed
    //evidenced by the number of times it notifies this observer
    int counter;
 
    public Observer()
    {
        counter = 0;
    }
 
    //counter is incremented with every notification
    public void Update() 
    {
         counter += 1;
    }
 
    //a getter for counter
    public int Counter
    {
        get
        {
            return counter;
        }
    }
}
//TESTER
using System;
 
public class ObserverTester
{
    [STAThread]
    public static void Main()  
    {
        Subject mySubject = new Subject();
        Observer myObserver1 = new Observer();
        Observer myObserver2 = new Observer();
 
        //register observers
        mySubject.RegisterObserver(myObserver1);
        mySubject.RegisterObserver(myObserver2);
 
        mySubject.Operate();
 
        //both observers are expected to yield 5 as a result of 5 notifications 
        Console.WriteLine("Observer 1 : {0} notifications.",myObserver1.Counter);
        Console.WriteLine("Observer 2 : {0} notifications.",myObserver2.Counter);
    }
}

This pseudocode, written in a Python-esque syntax, demonstrates the observer pattern.

class Listener:
    def init(self, name, subject):
        self.name = name
        subject.register(self)

    def notify(self, event):
        print self.name, "received event", event
class Subject:
    def init(self):
        self.listeners = []

    def register(self, listener):
        self.listeners.append(listener)

    def unregister(self, listener):
        self.listeners.remove(listener)

    def notify_listeners(self, event):
        for listener in self.listeners:
            listener.notify(event)
subject = Subject()
listenerA = Listener("", subject)
listenerB = Listener("", subject)
# the subject now has two listeners registered to it.
subject.notify_listeners ("")
# outputs:
#      received event 
#      received event 

The observer pattern can be implemented more succinctly in Python using decorators.

Here is an example that takes keyboard input and treats each input line as an event. The example is built upon the library classes java.util.Observer and java.util.Observable. When a string is supplied from System.in, the method notifyObserver is then called, in order to notify all observers of the event's occurrence, in the form of an invocation of their 'update' methods - in our example, ResponseHandler.update(...).

The file myapp.java contains a main() method that might be used in order to run the code.

/* File Name : EventSource.java */
 
package OBS;
import java.util.Observable;          //Observable is here
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
 
public class EventSource extends Observable implements Runnable
{
    public void run()
    {
        try
        {   
            final InputStreamReader isr = new InputStreamReader( System.in );
            final BufferedReader br = new BufferedReader( isr );
            while( true )
            {
                final String response = br.readLine();
                setChanged();
                notifyObservers( response );
            }
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
    }
}
/* File Name: ResponseHandler.java */
 
package OBS;
 
import java.util.Observable;
import java.util.Observer;  /* this is Event Handler */
 
public class ResponseHandler implements Observer
{
    private String resp;
    public void update (Observable obj, Object arg)
    {
        if (arg instanceof String)
        {
            resp = (String) arg;
            System.out.println("\nReceived Response: "+ resp );
        }
    }
}
/* Filename : myapp.java */
/* This is main program */
 
package OBS;
 
public class myapp
{
    public static void main(String args[])
    {            
        System.out.println("Enter Text >");
        // create an event source - reads from stdin
        final EventSource evSrc = new EventSource();
        // create an observer
        final ResponseHandler respHandler = new ResponseHandler();
        // subscribe the observer to the event source
        evSrc.addObserver( respHandler );
        // run the program
        evSrc.run();     
    }
}

The observer pattern is implemented in numerous programming libraries and systems, including almost all GUI toolkits.

Some of the most notable implementations of this pattern:


Advanced Search
Included Web Search Engines


Safe Search

close

Top Matching Results

Occasionally Search.com will highlight specialized results that are based on the context of your query. Examples of specialized results include specific links to news, images, or video.

Top Matching Results may highlight information from other Search.com pages, content from the CNET Network of sites, or third party content. The listings are based purely on relevance. Search.com does not receive payment for listings in this section but our partners that provide this data may get paid for listing these products.

Sponsored Links

This section contains paid listings which have been purchased by companies that want to have their sites appear for specific search terms and related content. These listings are administered, sorted and maintained by a third party and are not endorsed by Search.com.

Search Results

Search.com sends your search query to several search engines at one time and integrates the results into one list which has been sorted by relevance using Search.com's proprietary algorithm. You can customize the list of search engines included in your metasearch from the preferences.

The search engines that are used in your metasearch may allow companies to pay to have their Web sites included within the results. To view the Paid Inclusion policy for a specific search engine, please visit their Web site. Search.com does not accept payment or share revenue with any search engine partner for listings in this section.