November 1998

Return to Article Index

Understanding Object Relationships
By Jeffrey Hasan (Client Server Specialists, Inc.)


Introduction

As an object-oriented programmer, you put a lot of time and effort into designing useful objects. A good object is one whose purpose is well defined, and whose properties and methods are straightforward to use. However, not only is it important to have well designed objects in your application, but it is also important to clearly think out the relationships between the objects. Having a well-defined object model for your application makes your code easier to understand, plus you avoid duplicating functionality between individual objects.

Object relationships can be broadly broken down into 3 types: "Is a ...", "Has a ..." and "Uses a ...". In this article we discuss each relationship in turn, and then construct an object model to illustrate these principles in action. Read on, and as usual prepare to impress your friends ...

The "Is a ..." Relationship

The "Is a ..." relationship is the easiest for most of us to understand. Recall that an object is created based on a class module definition. Thus, the class module dictates what the object "Is". Consider the following:
Dim db As Database
Set db = New Database
And:
Dim Conn As New rdoConnection

Conn.EstablishConnection

In the first case, db is an object variable that "Is a" Database object, while Conn is an object variable that "Is a" RDO connection object. The declaration for db is an example of early binding, because the object is defined immediately following the Set statement. The declaration for Conn is an example of late binding, because the object will not be actually created until it is explicitly referenced in the code. In other words, an explicit reference to an object property or method later on will result in an implicit use of the Set statement (e.g., using the EstablishConnection method shown above).

The "Has a ..." Relationship

Objects are designed to have clearly defined functionality, and you should avoid duplicating functionality between objects. When one or more objects do need to have a common function, you should encapsulate that functionality in a separate object and reference it as needed from the other objects.

A good example of a "Has a" relationship is the one between a collection class and its members. Recall that a collection is a group of objects, and a collection is an object itself. To ensure good management of the collection, we write a collection class, which is simply a specialized class that is written to manage the collection. Using a collection class provides all of the OOP advantages we’ve come to know and love, namely, encapsulation of the code that manages the collection.


Remember, a collection class is there only to manage and organize similar objects. These objects must be based on the same class. For example, the "CTasks" collection manages objects based on the "CTask" class. It will not manage objects based on other classes. Collection classes do not provide properties or functions that in any way add to the functionality of the objects they manage. A collection class will typically have the following interface:

For more information on collection classes, please refer to my August 1998 VB Online article entitled "Managing Objects Using Collection Classes".

The "Uses a ..." Relationship

The "Uses a" relationship defines how one object uses another to accomplish a specific set of tasks. Take for example the case where several objects in your application need to use information from a back-end database. Rather than add SQL code to each object, it makes more sense to design a dedicated data access object whose sole function is communication with the back-end database. Dedicated objects are much easier to maintain and debug, code-wise, and having dedicated objects ensures that you don’t blur the functionality of any individual object. Remember, a single object should be handling a single set of tasks, and database access is a good example.

In a "Uses a" relationship, the calling object is referred to as the "client" object, while the called object is referred to as the "server" object. One server object may handle requests from several client objects.


The syntax for declaring a "Uses a" relationship depends on the nature of the server object. A data access object may need to persist for the lifetime of the application session, in which case, you would probably instantiate the server object as soon as the application loads, and terminate the object when the application ends. On the other hand, the server object may only need to persist as long as it is handling a request from a client object. In this case, the server object should have its instancing property set to "Private", and the client object should create and terminate the server object as needed.

Consider the "CData" server object above, and let’s say that it has 2 methods: "PutData" and "GetData", for storing and retrieving data to and from a back-end database. If a client object needs to access data, the syntax could be as follows:

Public Sub MyProc()
‘This is a method on the client object

‘Database data needed: declare an instance of the server object
Dim cd As New CData

‘Call the GetData method
cd.GetData 

‘Clear reference to server object
Set cd = Nothing

‘Continue with MyProc ...

End Sub
The advantages of this approach should be clear: only the server object needs to know details about the back-end database, and how to access it. The client objects need only be aware of the methods on the server object, i.e., its interface. Visual Basic’s IDE has the useful feature of providing you with a list of available methods and properties after you type the object variable and a period, plus the object browser provides a summary of available object interfaces.

Pulling It All Together: Object Models

Object-oriented applications are based on object models, which map out the available objects and the relationships between them. Several commercial tools are available to help you with this task, including Rational Rose and Microsoft’s Visual Modeler, based on Rational’s technology, which is currently only available with the Enterprise Edition of Visual Basic. These tools allow you to design object interfaces and visually map out an object model before you write your first line of code. They even provide an automatic code generation feature, which generates the basic framework code for your objects, and saves a good amount of initial development time.

An object model not only defines how objects relate, but also the number of objects involved in a relationship. For example, a collection class object has a one-to-many relationship with its members, that is, one collection object contains many member objects. A data access server object typically has a one-to-one relationship with its clients, because each client object will create one instance of the server object as needed. This is not always the case, a good example being a pool of RDO connection objects created by an object that needs to communicate with multiple remote data sources.

One way to think of object models is in physical terms, as represented by a car, for example. The car uses an engine, which is itself an aggregate of individual objects, such as the pistons and the battery. The engine has other objects. Similarly, the car uses wheels, or, it could be said, the car uses a collection of individual wheel objects. Immediately, you might question my choice of relationship terms: for example, a car could be said to have an engine, rather than uses an engine. This illustrates how there is no right way to define an object relationship. Instead, you make your own decisions, but be prepared to find that object models are always revised and refined as an application develops.

In general, I distinguish the "Has a" relationship from the "Uses a" relationship by deciding whether an object exists for the benefit of just one other, or whether it is available to several other objects. To me, the "Uses a" relationship denotes that the used object has a degree of independence. The data access server object, for example, exists for the benefit of several client objects, which is clearly a "Uses a" relationship. In the car example above, I define that a car uses a collection of wheels, which in turn has a collection of individual wheel objects. Wheel objects are "self-sufficient" objects which function whether they are attached to a car or not. Engine parts, on the other hand, aren’t as functionally independent, and are most useful if they are working as part of an engine. This to me is a clear "Has a" relationship. Probably the only unambiguous object relationship is the original "Is a" relationship.

In terms of coding, the difference between "Use a" and "Has a" relationships is most clearly reflected in the instancing property of the server object’s class module. A server object that exists for the benefit of just one client object should only be creatable by that client. The class module for the server object should be instanced private, and the object creation code for the server should only be found within the client code. The client creates and terminates the server as needed.

In a "Uses a" relationship, however, the instancing of the server object’s class module should be set to "Multiuse" or "Global Multiuse" as the case may be, and the creation code for the server may be found in several clients. Note that you only have this level of control over instancing if the class module resides in an ActiveX DLL or EXE. For a more thorough review of instancing and scope, please see my September 1998 VB Online article entitled "Using Scope, Instancing and Enumerations for Better OOP."

Conclusions

Object models are an essential aspect of object-oriented applications, and are especially important when multiple developers are involved, because they provide a blueprint for the project, and keep things focused by mapping out what the objects should look like and how they should relate. Constructing object models may not be second nature for many programmers, and in recognition of this, the commercial development packages mentioned above provide a Reverse Engineering feature which fits an object model to an existing, undocumented project.

If you are a Visual Basic programmer and plan on designing object-oriented applications, then you should seriously consider purchasing the Enterprise Edition of Visual Basic. In addition to Visual Modeler, it provides several other useful tools to help you manage your objects and components, including Visual SourceSafe, which allows you to check components in and out. This provides version control and makes it easier to manage multiple people working on a single application.



Copyright 1995-1998 VB Online. All rights reserved.