Publisher/Subscriber... practical benefits from event-driven patterns

Events are a critical component in Object Oriented programming. Whether they originate from user interaction or code logic, events are at the heart of what makes your application dynamic. Thanks to the advancement in both Java and .Net over the years, the event-driven paradigm has become possible on the web with the advent of JSF (Java Server Faces) and ASP.NET. Both of these technologies support the event-driven model allowing developers to take adantage of the "publisher/subscriber" pattern.

There are generally two types of events in Java and .NET; low-level events and semantic events.

Low-level events typically involve OS (GUI) type events such as Mouseclicks (onMouseClick, onMouseDown, etc) or keyboard actions (onKeyPress, onKeyDown, etc) whereas Semantic events are programmatic and involve the developer to create their own events, subsequently creating listeners to take custom actions based on those events. This article is geared toward utilizing semantic events.

What's the benefit of coding for semantic events?

That's a good question... let's take a typical application scenario and see how we can use events to develop a "real-world" solution.

Let's suppose we have an website that allows new users to register themselves (the event publisher). There are certain actions that need to happen when a new user has successfully completed the registration form (the event subscribers):

  • The database needs to be updated with the user's information.
  • The website owner needs to be notified that a user has registered and will need to approve the user before they can actually use the site.
  • The new user will need to be sent a "welcome to our site" type message.
  • The site will need to set a cookie in the user's browser so they will be "recognized" the next time they visit the site.

There are several ways to architect a suitable coding solution to meet these requirements, however by utilizing a publisher/subscriber design pattern we can create a scalable solution that will be flexible enough to handle any new actions that may be required at a later time. This is accomplished by firing an event when the user has registered. This will send out a notification to all subscribers of the "new user registration" event by way of a "callback" method. Each callback method would then be executed to perform their own specific tasks related to the new user registration. With this design in place, it becomes very easy to add new actions that may be required in the future by simply registering new callback methods to the "new user registration" event.

Java + .Net Demo 

Let's walk through a simple "Team Roster" demo to see the publisher/subscriber pattern in action. Here are the requirements for our application:

  • The application must be able to add new players to a team roster.
  • When a new player is added, we need to notify the coaching staff and the media
  • The application also must allow for new entities to be able to subscribe to new player notifications.

When reviewing the Java and C# code below you will notice that the code is very similar (same total lines of code in fact). One large difference is in the way the callback methods are handled. Java uses a single interface that all subscribing classes implement whereas .Net utilizes "Delegates."

NOTE: Delegates are similar to a "type-safe" function pointer in C/C++.

The "Team" class is considered the publisher in our demo. It contains the logic to actually "add" the player to the roster and then raises the event to notify the subscribers. The two listener classes (CoachListener and MediaListener) are then added to the event notfications. The "AddPlayerEvent" object is the actual class that is passed to the callback methods (with the new playername value).



   1:  using System;
   3:  namespace TeamRoster{
   5:      class AddPlayerEventArgs : EventArgs{ //create Event object
   6:          public string PlayerName { get; set; }
   7:      }
   8:      class CoachListener{
   9:          // subscribe callback method "NotifyCoachingStaff" to AddPlayerEvent (event) 
  10:          // using delegate "AddPlayerHandler" 
  11:          public void Subscribe(Team team){
  12:              team.AddPlayerEvent += new Team.AddPlayerHandler(NotifyCoachingStaff);
  13:          }
  14:          // create "Coach" Listener callback method
  15:          private void NotifyCoachingStaff(Team team, AddPlayerEventArgs e){
  16:              System.Console.WriteLine("To Coaching Staff: ({0}) was added to the team", e.PlayerName);
  17:          }
  18:      }
  19:      class MediaListener{
  20:          // subscribe callback method "NotifyMedia" to AddPlayerEvent (event) 
  21:          // using delegate "AddPlayerHandler" 
  22:          public void Subscribe(Team team){
  23:              team.AddPlayerEvent += new Team.AddPlayerHandler(NotifyMedia);
  24:          }
  25:          // create "Media" Listener callback method
  26:          private void NotifyMedia(Team team, AddPlayerEventArgs e){
  27:              System.Console.WriteLine("To Media Outlet: ({0}) was added to the team", e.PlayerName);
  28:          }
  29:      }
  30:      //publisher
  31:      class Team{
  32:          // delegate will hold a type-safe "pointer" to the callback 
  33:          // "Listener" callback methods
  34:          public delegate void AddPlayerHandler(Team team, AddPlayerEventArgs e);
  36:          public event AddPlayerHandler AddPlayerEvent; // event that callback methods will subscribe to
  38:          public void AddPlayer(string playername){ // method to add new player to roster
  39:              if (AddPlayerEvent != null){
  40:                  AddPlayerEventArgs e = new AddPlayerEventArgs();
  41:                  e.PlayerName = playername;
  42:                  System.Console.WriteLine("\nNew player added to the Roster, notifying all subscribers...");
  43:                  AddPlayerEvent(this, e); // call method to notify subscribers of new player
  44:              }
  45:          }
  46:      }
  47:      //main class
  48:      class AddTeamPlayer{
  49:          static void Main(){
  51:              Team team = new Team();
  52:              CoachListener coachlistener = new CoachListener();
  53:              MediaListener medialistener = new MediaListener();
  55:              coachlistener.Subscribe(team); // subscribe to event
  56:              medialistener.Subscribe(team); // subscribe to event
  58:              Console.Write("-Team Roster-\n");
  60:              team.AddPlayer("Memori"); // add player to roster
  61:              team.AddPlayer("Elias");
  62:              team.AddPlayer("Mikayli");
  63:              team.AddPlayer("Myranda");
  64:              team.AddPlayer("Elo");
  66:              Console.ReadLine();
  67:          }
  68:      }
  69:  }


 1 package TeamRoster;
 3 import java.util.*;
 5 class AddPlayerEvent extends EventObject { // Create event object
 6 	private String playername;
 7 	public String getPlayerName() { // getter method to return playername
 8 		return this.playername;
 9 	}
10 	// event constructor to set instance property
11 	public AddPlayerEvent(Object source, String playername) {
12 		super(source);
13 		this.playername = playername;
14 	}
15 }
16 // All listener classes will implement this interface
17 interface PlayerListener {
18 	void addPlayer(AddPlayerEvent addplayerevent);
19 }
20 // publisher
21 class Team {
22 	// method to add new player to roster
23 	public void AddPlayer(String playername) {
24 		System.out.println("\nNew player added to the Roster, notify all subscribers...");
25 		// call method to notify subscribers of new player
26 		OnAddPlayer(playername);
27 	}
28 	// method to notify all subscribers when a new player has been added
29 	// to the roster
30 	private void OnAddPlayer(String playername) {
31 		for (int i = 0, size = subscribers.size(); i < size; i++)
32 			((PlayerListener) subscribers.get(i)).addPlayer(new AddPlayerEvent(this, playername));
33 	}
34 	// type-safe ArrayList container to hold subscribers to the event
35 	List<PlayerListener> subscribers = new ArrayList<PlayerListener>();
36 	// method to add new subscribers to the ArrayList
37 	public void addPlayerListener(PlayerListener plistener) {
38 		subscribers.add(plistener);
39 	}
40 }
41 // main class
42 class AddTeamPlayer {
43 	public static void main(String[] args) {
44 		Team team = new Team();
45 		// create "Coach" PlayerListener callback class/method (Anonymous class)
46 		// approach
47 		team.addPlayerListener(new PlayerListener() {
48 			public void addPlayer(AddPlayerEvent e) {
49 				System.out.println("To Coaching Staff: (" + e.getPlayerName() + ") was added to the team");
50 			}
51 		});
52 		// create "Media" PlayerListener callback class/method (Inner class)
53 		// approach
54 		class MediaListener implements PlayerListener {
55 			public void addPlayer(AddPlayerEvent e) {
56 				System.out.println("To Media Outlet: (" + e.getPlayerName() + ") was added to the team");
57 			}
58 		}
59 		team.addPlayerListener(new MediaListener());
61 		System.out.print("-Team Roster-\n");
63 		team.AddPlayer("Memori"); // add player to roster
64 		team.AddPlayer("Elias");
65 		team.AddPlayer("Mikayli");
66 		team.AddPlayer("Myranda");
67 		team.AddPlayer("Elo");
68 	}
69 }

Here is the Console output from the .Net code:

Here is the Console output from the Java code:


posted on Friday, May 22, 2009 11:00 PM Print
# re: Publisher/Subscriber... practical benefits from event-driven patterns
1/10/2010 7:14 PM
nice example, cheers
# re: Publisher/Subscriber... practical benefits from event-driven patterns
energy suspension
6/22/2010 2:44 PM
say the even in qyestion was a query from a database like say a industry supplier like energy suspension bushings. would I be able to use this to bring a bout a nested array quesry fro cars and trucks perhaps? I think so aswesome!
# re: Publisher/Subscriber... practical benefits from event-driven patterns
6/2/2012 1:49 AM
It was very nice article... Can you explain me in detail.

Post Comment

Title *
Name *
Comment *  
Coding strategies for the Java and .Net developer...