Notification requires a notifier and at least one observer. Your code must instantiate these objects:
In the notifier, you must decide what interests you will allow observers to register for. Then, for each interest, you must perform the following steps:
In the observer, for each interest you wish to observe, you must perform the following steps:
The following sample demonstrates the use of interest-based, synchronous notification for nonframework components. That is, the default notifier and observer protocols of IModel and IModelView are not assumed.
Note: For an example of implementing notification for components, see the Model/View/Presenter Notification task.
myCustomer is an example of deriving from an IStandardNotifier. myCustomer encapsulates a name, address, and home phone. It supports getting and setting its fields and notifies any registered observers when the name, address, or home phone changes.
//Notification header files
#include <istdntfy.hpp>
#include <iobserv.hpp>
#include <inotifev.hpp
class myCustomer : public IStandardNotifier
{
public:
/**
* The constructor creates the three supported interests and enables
* notification. Any observer interested in a name change,
* address change, or home phone change will register with these
* interests.
*/
myCustomer()
:fNameChangedInterest (*this, nameId),
fAddressChangedInterest (*this, addressId),
fHomePhoneChangedInterest(*this, homePhoneId)
{
enableNotification();
}
virtual ~myCustomer() {};
virtual IString name() {return fName;}
virtual IString address() {return fAddress;}
virtual IString homePhone() {return fHomePhone;}
/**
* These are the setters for myCustomer. The setters will make the
* requested change and then notify observers by sending the
* appropriate interest via an INotificationEvent.
*/
virtual void setName(IString newname)
{
fName = newname;
notifyObservers(INotificationEvent(nameChangedInterest()));
}
virtual void setAddress (IString newaddress)
{
fAddress = newaddress;
notifyObservers(INotificationEvent(addressChangedInterest()));
}
virtual void setHomePhone(IString newphone)
{
fHomePhone = newphone;
notifyObservers(INotificationEvent(homePhoneChangedInterest()));
}
/**
* These are the getters for the three supported interest. Any observer
* interested in a name change, address change, or home phone change
* will register with these interests.
/*
IInterest& nameChangedInterest ()
{
return fNameChangedInterest;
}
IInterest& addressChangedInterest ()
{
return fAddressChangedInterest;
}
IInterest& homePhoneChangedInterest ()
{
return fHomePhoneChangedInterest;
}
private:
//Our data members
IString fName;
IString fAddress;
IString fHomePhone;
/**
* These are interest members corresponding to the observable
* data members
*/
IInterest fNameChangedInterest;
IInterest fAddressChangedInterest;
IInterest fHomePhoneChangedInterest;
//Declare the NotificationIds
static INotificationId const nameId, addressId, homePhoneId;
};
//Define the INotificationIds
const INotificationId IC_EXPORTB myCustomer::nameId
= "myCustomer::name";
const INotificationId IC_EXPORTB myCustomer::addressId
= "myCustomer::address";
const INotificationId IC_EXPORTB myCustomer::homePhoneId
= "myCustomer::homePhone";
myObserver is a class that receives notifications. It uses IObserverConnections to direct notifications to specific methods. In this example, it receives notifications from a customer object.
class myObserver
{
public:
/**
* constructor for observer
*/
myObserver (myCustomer& aCustomer);
virtual ~myObserver();
/**
* handler method to handle any change in the customer
*/
virtual void handleAnyChange (const INotificationEvent& anEvent)
{
printf (">> Why hello, myObserver::handleAnyChange just
received the event: %s \n", anEvent.notificationId());
}
/**
* handler method to handle just name changes in the customer
*/
virtual void handleNameChange (const INotificationEvent& anEvent)
{
printf (">> Why hello, myObserver::handleNameChange just
received the event: %s \n", anEvent.notificationId());
}
private:
// for each event you are interested in, create a connection object
IObserverConnectionTo<myObserver> fAnyChangeConnection;
IObserverConnectionTo<myObserver> fNameChangeConnection;
myCustomer& fCustomer;
};
/** * connect this observer to the given customer notifier */
myObserver::myObserver(myCustomer& aCustomer) :
fCustomer(aCustomer),
//all events trigger this method
fAnyChangeConnection (*this, myObserver::handleAnyChange),
//only name change events trigger this method
fNameChangeConnection (*this, myObserver::handleNameChange)
{
//this connection handles all notifications from aNotifier
fAnyChangeConnection.handleNotificationsFor(fCustomer);
//this connection handles only name change notifications from aNotifier
fNameChangeConnection.handleNotificationsFor
(fCustomer.nameChangedInterest());
}
/** * unregister from receiving events from the customer */
myObserver::~myObserver()
{
fAnyChangeConnection.stopHandlingNotificationsFor(fCustomer);
fNameChangeConnection.stopHandlingNotificationsFor(fCustomer);
}
int main()
{
myCustomer theCustomer;
myObserver theObserver(theCustomer);
//should trigger handleAnyChange/handleNameChange
theCustomer.setName("Bubba Malone");
//should only trigger handleAnyChange
theCustomer.setAddress("1999 IBM Way");
}
Here is the output from the program:
>> Why hello, myObserver::handleAnyChange just received the event:
myCustomer::name
>> Why hello, myObserver::handleNameChange just received the event:
myCustomer::name
>> Why hello, myObserver::handleAnyChange just received the event:
myCustomer::address
To notify asynchronously, follow the same steps as for synchronous notification, substituting a call to notifyObserversAsync() for notifyObservers(). You can implement truly asynchronous notification by putting the notifier and the observer in different threads.
To pass event data along with a notification of the event, follow the same steps for basic notification, except:
notifyObservers(INotificationEventFor<MyEventDataClass>& event, myAlertInterestFunction(), new myEventDataClass());
for this version:
notifyObservers(myAlertInterestFunction());
IObserverForConnectionTo<myObserver> myDataChangeConnection;
for this template:
IObserverConnectionTo<myObserver> myDataChangeConnection;