Exploiting data module form inheritance

by Mark Cashman

I the article “Designing with data modules,” I explained how form inheritance can be used to separate edit and lookup access to a database, and to defer or allow inheritance structures that implement different decisions about the type of datasets to be used.

Inheritance can also be used as a more comprehensive system-structuring technique. Such a technique is based on the ability to override and augment event handlers in descendant forms.

As you may know, descendant forms can contain components not present in the base form class. In addition, property values can be changed. However, it is not possible to replace a component with a descendant. So component inheritance cannot be used to augment the data module, except insofar as it produces additional components to be added to the descendant data module.

This problem can be overcome through the use of event handlers. If your base class component is designed as a framework to hold event handling logic, then descendant data modules can augment those capabilities. Indeed, the base data module can simply contain the components without any event handling logic, much as an abstract class contains abstract member functions to be implemented by descendants.

Let's use a concrete example to see how this might work. Imagine a data module that contains an incoming and outgoing communication component and a set of processing components that operate on a standard data structure. Figure A shows a data module that illustrates this type of arrangement.

Figure A

This data module is used for processing communications.

The data module uses two instances of a custom component class, TCommunicationComponent, that has an assignable data property, and an OnAssign event that is triggered by the setter function when data is assigned to that property. It also has an instance of a custom component class called TProcessor, which also exposes an assignable data property. It has a method called Perform() that does nothing but invoke an event handler for the ToProcess event.

The base class data module has logic in the IncomingCommunication component’s OnAssign event that passes the assigned data along to the Process component and calls the Perform() method. The ToProcess event of the base class data module then does nothing but assign the data to the OutgoingCommunication component.

This framework can be extended in a number of descendant data modules. For example:

This technique has the advantage of making a framework explicit at design time, of offering customization points (sometimes called hinges) in the form of event handlers, and of offering opportunities to support specialized event handlers with other components introduced in descendant classes.

Obviously, you can start with more or less specialized frameworks in the base class, and expand them to be as complex and elaborate both horizontally and vertically as needed.