Previous Section  < Free Open Study >  Next Section

8.1 Introduction to Class-Specific Versus Object-Specific Data and Behavior

When teaching an object-oriented design course, I often ask the question, "Is an object required when you wish to send a message?" Invariably, the response is "Of course, messages are sent to objects." Since the constructor of a class is one of its messages, how does one build the first object? It is clear that the constructor is a different sort of message. It does not require an object before it can be sent. (In the case of C++, the constructor is considered a normal message sent to an object that the standard allocator has created. For the purpose of this discussion, I consider my use of the term "constructor" to include standard allocation and initialization).

Another example of this phenomenon can be found in the design of an Invoice class. What pieces of data does each invoice object require? Some common data members of invoices include the billing address, the return address, line items, the total value, etc. Each invoice object must get its own copy of this data. In addition, each invoice has the behaviors of adding items, deleting items, and printing. These three operations require a target invoice object in order to execute. These data and behaviors are considered object-specific, since each object gets a unique copy of the data and only objects have access to the behaviors.

There is another piece of data that each invoice object must possess: a unique invoice number. Again, each invoice object must have its own copy. Who decides the value of this invoice number? There must be some counter that keeps track of the last invoice number. When an invoice object is constructed, this counter is incremented and the invoice number of the object is assigned the new value. Who owns this counter? Certainly not the invoice object, since there is only one invoice counter for all of the objects. The obvious choice is the Invoice class. In fact, whenever there is bookkeeping to be performed on the objects of the class, then that class should store the necessary data. In addition, we may want to know what the next invoice number is going to be. This should not be an object-specific behavior, since there may be no invoice objects at the time we wish to examine the next invoice number. It would be inconvenient, at best, to build an invoice object just to ask it the value of the next invoice number. Of course, there is also the problem that the action of getting that number will waste an invoice. The obvious entity to ask is the Invoice class. It knows the value of the next invoice number whether or not any invoice objects currently exist in the system.

The invoice counter is an example of class-specific data. A piece of class-specific data is often called a class variable. Class variables are used to store information concerning the objects, not an individual object, of the class. Whenever a developer is using global data within the methods of a class, he or she should determine if a class variable would be more appropriate.

The constructor and the GetNextInvoiceNum-type methods of the Invoice class are examples of class-specific behaviors. A class-specific behavior is often called a class method. A class method is used whenever behavior accesses only class variables within a class. If no object-specific data is being accessed, a class designer should ask himself if the operation really belongs to the class itself, as opposed to the objects of the class.

Heuristic 8.1

Do not use global data or functions to perform bookkeeping information on the objects of a class. Class variables or methods should be used instead.

    Previous Section  < Free Open Study >  Next Section