Several new classes will be introduced to illustrate building systems by association. These classes are a simple incrementing or decrementing counter, several kinds of buttons, and a simple timer. Though these classes are simple, they can be configured to form a number of interesting systems. The classes are also very specialized because only a part of the C++ language is being used to defined them. Techniques that will be learned later can be used to extend the generality of these classes.
The class Counter models a simple integer counter that can count upwards or downwards depending on how it is constructed. The Counter displays its current value in a Message. If the Message object is itself displayed in a Frame object, the value of the Counter object will appear on the display. The Reset method allows the Counter object to be returned to its original state. The class definition is:
The Counter Class |
---|
class Counter { private: // encapsulated implementation goes here public: Counter (int start, int end); // count up/down from start to end Counter(); // count upwards from zero void Next(); // increment/decrement by 1 void Reset(); // reset to original state void ConnectTo(Message& msg); // show current value here ~Counter(); // destructor };
|
In the first constructor, the Counter counts upwards by one if start is less than stop and it counts downward by one otherwise. The second constructor defines a counter that counts upward by one without bound. The current value of the Counter is displayed in the Message object specified in the ConnectTo method. The current value of the Counter is incremented or decremented by the Next method. Whenever the value of the Counter is changed by the Next method, the Message object, if any, to which the Counter object is connect is updated accordingly using the Message object's ChangeMessage method. The Reset method causes the Counter object to be restored to it initial state.
A simple system that counts left mouse click events is shown in the code below. This system uses a Counter to count the number of left mouse click events, a Message object to display the Counter object's current value, and a Frame object to make this display visible to the user.
Frame window("Counter", Location(100,100), Shape (200,200)); Message countDisplay("", Location(10,10)); Counter clickCount; void OnStart() { countDisplay.DisplayIn(window); clickCount.ConnectTo(countDisplay); } void OnPaint() { countDisplay.Draw(); } void OnTimerEvent() {} void OnMouseEvent() {char *frameName, int x, int y, int buttonState) { if (buttonState & leftButtonDown) { clickCount.Next(); } }
There are two significant things to observe in this example:
When the Next event in the Counter object is called, a series of actions is triggered among the parts of the system so that the Counter object's interal count is incremented, its corresponding Message representation is changed, and the Message object changes what is being displayed in the Frame object visible to the user.
The Clock class is an abstraction of the system's interval timer. The Clock class increments a Counter at fixed intervals of time. The resolution of the Clock (i.e., the timer's interval) is set on construction. The Clock can be started and stopped. The definition of the Clock class is:
The Clock Class |
---|
class Clock { private: // encapsulated implementation goes here public: Clock (int interval); // milliseconds between "ticks" void ConnectTo(Counter & count); // change count on each "tick" void Start(); // (re)start Clock void Stop(); // halt Clock };
|
The constructor specifies the interval of time, in milliseconds, between successive clock "ticks". On each "tick" of the clock, the Clock calls the Next method in the Counter to which the Clock is connected. The connection between the Clock and a Counter is established by the ConnectTo method. The Start and Stop methods can be used to control the Clock.
An example of how a Clock and a Counter can be used to build a simple timer systems is the following:
Frame window ("Timer", Location(100, 100), Shape(200, 200)); Message label("Seconds:", Location(10,10)); Message display("", Location(100,10)); Counter seconds; Clock timer(1000); void OnStart() { timer.ConnectTo(seconds); second.ConnectTo(display); display.DisplayIn(window); timer.Start(); } void OnPaint() { display.Draw(); } void OnTimerEvent() {} void OnMouseEvent() {char *frameName, int x, int y, int buttonState) {}This examples creates a one second Clock connected to a Counter that counts upwards from 0. The value of the Counter is presented in a Message labeled "Seconds" that is visible in the window Frame.
To allow systems to be created that give the user interactive control three button classes will be defined. These buttons can be composed with the Clock and Counter classes to form several small, but interesting systems.
The three button classes are very similar, each being specialized to a particular purpose. Two of the button classes allow the user to start and stop a Clock and the third allows the user to reset a Counter. The definitions of these classes is as follows:
class StartClockButton { private: // encapsulated implementation goes here public: StartClockButton(char* label); // label of button on screen void ConnectTo(Clock& t); // start this Clock ~StartClockButton(); // destructor }; class StopClockButton { private: // encapsulated implementation goes here public: StopClockButton(char* label); // label of button on screen void ConnectTo(Clock& t); // stop this Clock ~StopClockButton(); // destructor }; class ResetCounterButton { private: // encapsulated implementation goes here public: ResetCounterButton(char* label); // label of button on screen void ConnectTo(Counter& t); // reset this counter ~ResetCounterButton(); // destructor };These classes are very specialized. Techniques will be studied later that will allow classes that are so similar to be defined in a more general way.
Objects of the button classes need to be made visible to the user in some window. The Frame class is again extended to include methods for displaying button objects. As before, the Display method is overloaded. Only the most relevant methods are shown below.
class Frame { private: // encapsulated private implementation public: void Display(Message msg); // show message in window void Display(TextBox& box); // show text in window void Display(StartClockButton& button); // show button in window void Display(StopClockButton& button); // show button in window void Display(ResetCounterButton& button);// show button in window };The Frame class definition is clearly becoming populated with many methods. Having a separate overloading of the Display method for each distinct kind of button will quickly become intolerable - imagine how many different kinds of buttons you have seen in user interfaces. Fortunately, other parts of object-oriented programming and C++ are available, and will be seen shortly, that will remedy this problem.
A small system that allows the user to control a counter extends the simple example above by adding a button to start the Clock.
//declarations Frame window (Location(100, 100), Shape(300, 200)); TextBox display(Location(10,10), Shape(150, 50), "Seconds:"); Counter seconds; Clock timer(1000); StartClockButton start("Push to Start"); // code start.ConnectTo(timer); timer.ConnectTo(seconds); seconds.ConnectTo(display); window.Display(display); window.Display(start);This system is the same as the one developed above except that the program control of when the Clock is started has been replaced by interactive user control.
The concepts of building a system of interacting objects using association are illustrated by this applet .
|
Exercises |