|
Figure 2 illustrates a simplified
class design in Booch notation for handling TButton user actions. (See the reference
to Grady Booch at the endnotes for more information on his notation.) As shown, TMacroButton
is inherited from TButton and contains a macro stored in a string (aggregate "by
value" association) and a boolean property (also "by value") indicating
whether or not the macro is being recorded or played back. The TMacroButton would,
when recording, record the TButton's Click events until recording was turned "off."
When playback was turned "on," TMacroButton would generate the TButton's
OnClick events for each "click" present in the recorded macro.
In similar fashion, macro recorders
could be built for checkboxes, radio buttons and other controls. The components could
be extended to make use of a global macro string so that all the individual macro
strings could be weaved onto a single macro string. Properly exposing the OnClick
events to application developers using this approach would require that the component
designer create a descendant class hierarchy based on all of the controls that could
be used to record macros. In most cases building whole new inheritance hierarchies
is neither practical, nor desirable. No, this approach would take us back to aggregation
and not forward towards links and a single component solution.
A better solution approach would
involve a single component, that when dropped on the form would provide the macro
recording and playback capabilities, yet would also permit all the buttons on the
form to retain their original design and run-time behavior. But remember, One click
per customer is the rule. That's the rub. Only the button knows when it gets clicked.
How does the button inform the macro recorder component? How would the button even
know about the existence of the macro recorder?
The macro recorder could override
the button's OnClick event, but then the OnClick event is no longer available to
the application designer. The button and macro recorder must be able to collaborate,
yet retain their individual strengths. They must establish a synergistic relationship.
If these issues sound scarcely similar
to challenges you are now facing or that you have faced in the past, they should.
Many OOP design dilemmas when approached with traditional thinking create unwieldy
class hierarchies or unworkable designs. By dynamically overriding event handlers
you can break through the aggregate mindset and create synergistic components. Let's
consider a link-based way to build the macro recorder.
|