Click here to Skip to main content
Licence CPOL
First Posted 31 Aug 2009
Views 8,625
Downloads 42
Bookmarked 13 times

Speaker-Listener

By | 31 Aug 2009 | Article
The Speaker Listener design pattern.

Introduction

The Speaker-Listener Design Pattern allows to add new operations to existing objects without modifying the structure of the objects. In essence, the pattern allows to the interested parties (the listeners) to be notified when an event has occurred and gives them a chance to take actions.

Background

This pattern follows the open/closed principle which states that "software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification" -- The behaviour of the speaker object (and the algorithm which it implements) can be modified without altering its source code. This saves the effort and the precious time on testing, code reviews, and debugging.

Using the code

The Speaker object sends events to parties interested in receiving Listener events.

First, we have to decide what events the speaker should fire. A Listener is a class that has one or more functions with the following signature:

public : void on( Event event , ... ) throw();

class SimpleListener {
public:
  // The event class
  template<int>
  class Event {
  };
  enum id {
    EVENT_ADD,  // for Event<event_add> event class
    EVENT_SUB   // for Event<event_sub> event class
  };

  // The events. 
  virtual void on( Event<event_add> event , int x , int y) = 0;
  virtual void on( Event<event_sub> event , int x , int y) = 0;
};

In order to add to speaker object the capability to send events, we inherit from Speaker<SimpleListener>. By calling fire() when an event has occurred, we notify the registered listeners about the event and allow them to take actions.

class SimpleSpeaker: public Speaker<SimpleListener> {
  public: void add(int x, int y) {
    printf( "Speaker : add %d and %d\n",x,y);
    fire( SimpleListener::Event<SimpleListener::EVENT_ADD>() , x , y );
  }
  public: void sub(int x, int y) {
    printf( "Speaker : sub %d and %d\n",x,y);
    fire( SimpleListener::Event<SimpleListener::EVENT_SUB>() , x , y );
  }
};

To create listener classes, we inherit from SimpleListener. Let's create two listener classes that print messages to the screen.

class Listener1 : public SimpleListener {
public:
  virtual void on( Event<EVENT_ADD> event , int x , int y){
    printf( "L1: add %d and %d\n",x,y);
  }
  virtual void on( Event<EVENT_SUB> event , int x , int y){
    printf( "L1: sub %d and %d\n",x,y);
  }
};

class Listener2 : public SimpleListener {
public:
  virtual void on( Event<EVENT_ADD> event , int x , int y){
    printf( "L2: add %d and %d\n",x,y);
  }
  virtual void on( Event<EVENT_SUB> event , int x , int y){
    printf( "L2: sub %d and %d\n",x,y);
  }
};

To be notified about the events, the listener object should be registered with addListener of the speaker object. To stop being notified, use removeListener() and removeListeners().

int main() {
  SimpleSpeaker ss;

  ss.addListener( new Listener1() , true ); // the true - the speaker is owner of the listener
                                            // and should delete it when it goes out of scope.
  ss.add(1,2);
  ss.addListener( new Listener2() , true );
  ss.sub(3,4);
  ss.removeListeners(); 
  ss.sub(3,4);
}

Summary

Although Boost.Signals is a good implementation to this pattern, I found that my implementation is more simple to use. The relationships between the objects are documented in the code, thereby creating more readable and maintainable code.

License

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

About the Author

zebrot

Software Developer

Israel Israel

Member

I have been developing professionally since 2002. I developed desktop applications in C++ and C#. Now developing web applications and sites in PHP and Ruby.
 
My blog is located in http://www.zebrot.com

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board. (secure sign-in)
 
Search this forum  
 FAQ
    Noise  Layout  Per page   
  Refresh
GeneralMy vote of 1 PinmemberGrump6:39 8 Sep '09  
GeneralThis is the same pattern - just different naming ... [modified] Pinmemberbigsigma3:59 9 Sep '09  

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.

Permalink | Advertise | Privacy | Mobile
Web01 | 2.5.120517.1 | Last Updated 31 Aug 2009
Article Copyright 2009 by zebrot
Everything else Copyright © CodeProject, 1999-2012
Terms of Use
Layout: fixed | fluid