The Many (Inter)Faces of Code Reuse

See Also

There are two main forms of code reuse — binary and source. Binary code reuse is accomplished by creating and using an object, while source code reuse is achieved by inheritance, which isn't supported by Visual Basic. (Source code reuse can also be achieved by copying and modifying the source code, but this technique is nothing new, and has many well-known problems.)

Visual Basic has been a pioneer of binary code reuse — controls being the classic example. You reuse the code in a control by placing an instance of the control on your form. This is known as a containment relationship or a has-a relationship; that is, the form contains or has a CommandButton.

For More Information   Containment relationships are discussed in "Object Models" later in this chapter.

Delegating to an Implemented Object

Implements provides a powerful new means of code reuse. You can implement an abstract class (as discussed in "Creating and Implementing an Interface"), or you can implement the interface of a fully functional class. You can create the inner object (that is, the implemented object) in the Initialize event of the outer object (that is, the one that implements the inner object's interface).

As noted in "Creating and Implementing an Interface," an interface is like a contract — you must implement all the members of the inner object's interface in the outer object's class module. However, you can be very selective in the way you delegate to the properties and methods of the inner object. In one method you might delegate directly to the inner object, passing the arguments unchanged, while in another method you might execute some code of your own before calling the inner object — and in a third method you might execute only your own code, ignoring the inner object altogether!

For example, suppose you have a OneManBand class and a Cacophony class, both of which generate sounds. You'd like to add the functionality of the Cacophony class to the OneManBand class, and reuse some of the implementation of the Cacophony class's methods.

' OneManBand implements the Cacophony interface.
Implements Cacophony

' Object variable to keep the reference in.
Private mcac As Cacophony

Private Sub Class_Initialize()
   ' Create the object.
   Set mcac = New Cacophony
End Sub

You can now go to the Object drop down and select Cacophony, and then get procedure templates for the methods of the Cacophony interface. To implement these methods, you can delegate to the Cacophony object. For example, the Beep method might look like this:

Private Sub Cacophony_Beep(ByVal Frequency As Double, _
ByVal Duration As Double)
   ' Delegate to the inner Cacophony object.
   Call mcac.Beep(Frequency, Duration)
End Sub

The implementation above is very simple. The outer object (OneManBand) delegates directly to the inner (Cacophony), reusing the Cacophony object's Beep method without any changes. This is a good thing, but it's only the beginning.

The Implements statement is a very powerful tool for code reuse, because it gives you enormous flexibility. You might decide to alter the effects of the OneManBand class's Beep method, by inserting your own code before (or after) the call to the inner Cacophony object:

Private Sub Cacophony_Beep(ByVal Frequency As Double, _
ByVal Duration As Double)
   ' Bump everything up an octave.
   Frequency = Frequency * 2
   ' Based on another property of the OneManBand 
   ' class, Staccato, cut the duration of each beep.
   If Staccato Then Duration = Duration * 7 / 8
   Call mcac.Beep(Frequency, Duration)
   ' You can even call other methods of OneManBand.
   If Staccato Then Pause(Duration * 1 / 8)
End Sub

For some of the methods, your implementation may delegate directly to the inner Cacophony object, while for others you may interpose your own code before and after delegating — or even omit delegation altogether, using entirely your own code to implement a method.

Because the OneManBand class implements the Cacophony interface, you can use it with any musical application that calls that interface. Your implementation details are hidden from the calling application, but the resulting sounds are all your own.

Note   COM provides another mechanism for binary code reuse, called aggregation. In aggregation, an entire interface is reused, without any changes, and the implementation is provided by an instance of the class being aggregated. Visual Basic does not support this form of code reuse.

Doesn't This Get Tedious?

Writing delegation code can indeed become tedious, especially if most of the outer object's properties and methods simply delegate directly to the corresponding properties and methods of the inner object.

If you have the Professional or Enterprise Edition of Visual Basic, you can use the Visual Basic Extensibility model to create your own delegation wizard to automate the task, similar to the Class Wizard that's included in the Professional and Enterprise editions.

For More Information   The use of polymorphism and multiple interfaces in component software is discussed in "General Principles of Component Design" in Creating ActiveX Components in the Component Tools Guide.

Using the Extensibility Model is documented in Extending the Visual Basic Environment with Add-Ins in the Component Tools Guide.