Making our customers successful
with what we do best:
Create best-of-class software
for Windows and Linux.

 

About Us Contact Us Free Stuff

Increase Productivity and Reliability of your software with a set of C++ class templates.

Any non-trivial software program faces the challenge of keeping all parts of the program in a consistent state. Consider this scenario: Your software allows you to view results of a database query. Those results may be seen in more than one view. In the upcoming revision you decide to now give your customer a new option: display headers with normal face or bold face. We assume that this new feature is implemented with a Boolean variable whose value determines if the headers are printed bold or not. 

What are the possible approaches to have all views of the report be updated when the variable changes? Here are a few:

  • Whatever part of your program modifies the variable is also required to call a method in each view. This approach requires that from now on every time this variable is modified anywhere, your programmers must also call all views to get them updated. It also means that if you decide to create a new kind of view that you have to go to every part of your program that modifies the variable and upgrade the code so that this new view is properly handled.

  • Provide a mutator function and make sure that the variable can only be modified through this function. Now there is only one place in your code where the view notification must be maintained. However, each of your variables needs a mutator function which pretty much replicates what the other ones do.

  • Provide a class that encapsulates the variable and that has a notion of attached "views" that it needs to notify when its value changes. Furthermore, in C++ the use of templates make it possible to write the code for this class once (as a template) and use it for different types of variables. Component Software has developed two sets of class templates for this purpose. This article describes both sets.

WiredVar / NotificationClient family of classes

WiredVarT<> is a template, which contains one member (m_v) of type T. M_v contains the current value of the variable. Assignment operator and T operator are provided so that the WiredVar can be used as if it were a simple variable of type T. WiredVarT subclasses from WiredVar. WiredVar maintains a list of notification clients. The job of WiredVarT is to use WiredVar whenever the value of m_v changes.

NotificationClient is  an abstract class which works with WiredVar. Classes that want to become notification clients must implement this interface. Of particular importance is the VarChanged method in NotificationClient. It is this method that WiredVar will call when the content of its m_v changes.

Notification clients register and unregister with the wired variable through the RegisterClient and UnregisterClient methods. This can be done at any point in the lifetime of the program.

While a notification client is registered with a wired variable, it will receive update notifications on its VarChanged method. Since a notification client may be registered with more than one wired variable, Varchanged may be called from multiple notification clients at different times. To allow identification identification, VarChanged contains a pointer to its caller.

 

Wire aggregator class

An extension of the wired variable / notification client family is the wire aggregator. Its job is to collect notifications for a number of wired variables into one single notification. Using an aggregator class has the advantage that there is only one place in the program where a new wired variable must be added to a notification client, and many notification clients will instantly be notified of changes in the new wired variable.

Consider this example: Suppose that you have a program that has a number of variables implemented as wired variables. Without the wire aggregator, each view would need to register with each wired variable. If a new wired variable is added to your program, all views will need to be upgraded to now register with this new variable. With the wire aggregator, the views only register with the wire aggregator, and the wire aggregator is the only object that must be upgraded to now register with the new wired variable. When the wire aggregator calls its notification clients, it puts a pointer to itself into the call to the VarChanged method. Experience has shown that this is practical in most, but not all cases. For this reason, the VarChanged has two arguments: The first one is the immediate caller of VarChanged, the second argument is usually used to communicate the wired variable that has caused the VarChanged. If the notification client has a need to know the original wired variable, it can use the second argument for that purpose.

 

GUI adapters for notification clients

Wired variables have been used in a number of projects at Component Software. Some of these projects are GUI applications. To facilitate the use of wired variables in GUI views, a set of adapters have been created to connect a wired variable to a control on the screen. In particular, there have been adapters for text edit boxes, list boxes, combo boxes, and sliders. Their implementation is in two stages: The first stage, implementing the logical functionality and the interface to the wired variable is done as a partially-implemented class (WiredControl). One of its methods, UpdateGUI, is a pure virtual class, which must be implemented by the operating system. This approach allows the GUI adapters to be used in different graphical environments (MS Windows/MFC and gtk  are currently supported, Mac OSX Carbon is in the development stage) with minimal OS-specific code. WiredControl allows subclasses access to their associated WiredVar. This is typically used by event notification handlers to modify the WiredVar in response to user modifying data through the program's GUI.

 

Param/AgentOfSupervisor/Supervisor class family

A second set of class templates are the ParamT, AgentOfSupervisor, and Supervisor templates. Their use is similar to the wired variable/ notification client, but differs in the fact that the relationship between ParamT and one or more AgentOfSupervisors is established at construction time and not changeable. Correct construction is enforced by the compiler. ParamTs also don't have to have a "home." They are implemented in a way that they exist as long as there is 1 or more AgentOfSupervisors that are attached to it. Once the last attached AgentOfSupervisor is destroyed, the ParamT is destroyed with it.

AgentOfSupervisors have a SetV and GetV function, rather than assignment and T operators. In the case of the application for which this class family was created it was a better approach, but for other applications the SetV and GetV methods can easily be replaced by operators. AgentOfSupervisors have a Supervisor. This relationship is established during construction. Typically an AgentOfSupervisor is placed as a member in a class, and that class then is the Supervisor.

 

Source code

The source code (available for Windows/MFC, Unix/X11/gtk, and Mac Cabron) implements a small example of the WiredVar/Notification client class template, in which observers in multiple views are attached to multiple wired variables.

Bibliography

Design Patterns, Gamma et. al. ISBN 0-201-63361-2


Has this page been helpful to you? 
Do you have questions or comments?

We would very much like to hear from you. Just send us your thoughts below, or send us an e-mail at support@componentsw.com

Thank you!

 

Contact Name
Contact E-mail

Your feedback

Copyright © 2002-2005 Component Software, Inc.
All Rights Reserved

 


Helping Build the Tech Oasis - http://www.techoasis.org