|
1. Defining the Object Model
1.6 Inheritance
At the start of this chapter, it was mentioned that defining a class for ReStore enables a database table to be automatically constructed for that class.With a hierarchy of related classes, it is necessary to decide whether these should share a single database table, or should each class exist in its own individual table (or possibly some combination of both). By default, a hierarchy of classes will share a single table.
To illustrate the concepts discussed in this section, we will consider the StockItem hierarchy from the Entertainment Shop example application; it is worthwhile studying this before proceeding:
StockItem - code, title, price, numberInStock CompactDisc - artist, tracks VHSVideo - director, genre DVDVideo - extrasDescription
Advantages of Sharing a Table
When a hierarchy of classes share a single table, some important possibilities are opened up. Firstly, if you define an instance variable in another class as holding instances of the superclass of a hierarchy (StockItem in the case of our example), then in fact that instance variable can hold an instance of the superclass or any of the subclasses sharing the superclass table. In the Entertainment Shop application, this is done in the OrderItem class definition method:aTableaddClassDefinitionTo:
aTable
define: #stockItem as: StockItem;
define: #price as: (ScaledDecimal withPrecision: 8 scale: 2);
define: #isStockAllocated as: Boolean
Thus an OrderItem can hold a CompactDisc, a VHSVideo or a DVDVideo instance in its stockItem instance variable.
A second advantage is that when you need to query for objects in the database, then a query for instances of the superclass of the hierarchy will also find instances of any subclasses sharing that table. Again, the Entertainment Shop application takes advantage of this in the class StockItemFinder:
"Find StockItems using the title and type infor input by the user.findItems
| found numberFound |
found := self
reStore instancesOf: StockItem satisfying: [
:item | self title match: item
title].
...
This method will in fact find instances of CompactDisc, VHSVideo or DVDVideo.
A final advantage of sharing a table amongst a hierarchy of classes is that, should you need to query the database from a source other than your Smalltalk application (a reporting tool, for example), then this may be simplified by the fact that all the objects are located within one table.
Disadvantages of Sharing a Table
When constructing the single shared table for a hierarchy of classes, ReStore
will allocate a column for every (non-collection) instance variable in each
class. Thus, when for example an instance of VHSVideo is stored in the table,
the columns corresponding to artist (a CompactDisc variable) and
extrasDescription
(DVDVideo) will be empty. This is effectively wasted space in the table.
If there are large differences in the instance variables held by different subclasses within a hierarchy, you should possibly consider storing the subclasses in different tables to avoid this waste of space. This does mean that the advantages of table sharing listed above are lost. However, if there are large differences between the classes in the hierarchy, then it is likely that they are not related in a meaningful way and so the loss of these advantages may not be important.
A common situation where this is the case is where there is one abstract superclass, defining a few common attributes, for all model object classes in a particular application. Example:
MyModel | - description, dateCreated |
Person | - surname, firstName, address... |
Address | - line1, postcode, city... |
Product | - name, code, location... |
In a case like this, then it is highly unlikely that you would want instances of Person, Address and Product to share a table. To turn off the default behaviour of hierarchies sharing a table, MyModel should implement the following simple class method:
shouldSubclassesInheritPersistency
^false
Should you wish to turn table sharing 'on' again in a sub-hierarchy, you would simply override this method to return true.
Alternatively, or in addition to this, individual subclasses may choose to 'opt out' of sharing a table by implementing the following method:
shouldInheritPersistency
^false
Note, however, that a subclass cannot 'opt in' to table sharing where it has been specifically turned off by a superclass implementation of shouldSubclassesInheritPersistency.
The use of these two methods is documented further in their implementation as Object class methods, where the default behaviour is defined.
Don't forget super
Whether sharing a table or not, it is important that when
subclasses implement their addClassDefinitionTo:
method they should also forward the method on to their superclass in order to
include the definition of the superclass's own instance variables. Example:
CompactDisc:
aTableaddClassDefinitionTo:
aTable
define:
#artist as: (String
maxSize: 200);
define:
#tracks as: (OrderedCollection
of: CDTrack).
^super addClassDefinitionTo: aTable
StockItem:
aTableaddClassDefinitionTo:
aTable
define:
#code as: (String
fixedSize: 12);
define:
#title as: (String
maxSize: 200);
define:
#price as: (ScaledDecimal
withPrecision: 8
scale: 2);
define:
#numberInStock as: Integer
1.6 Inheritance