Next: The Checking class, Up: Creating subclasses
We create the Savings class as a subclass of Account. It holds money, just like an Account, but has an additional property that we will model: it is paid interest based on its balance. We create the class Savings as a subclass of Account.
Account subclass: Savings [ | interest |
This is already telling something:
the instance variable interest
will accumulate interest
paid. Thus, in addition to the spend:
and
deposit:
messages which we inherit from our parent,
Account, we will need to define a method to add in interest
deposits, and a way to clear the interest variable (which
we would do yearly, after we have paid taxes). We first define
a method for allocating a new account—we need to make sure that the
interest field starts at 0.
We can do so within the Account subclass: Savings
scope,
which we have not closed above.
init [ <category: 'initialization'> interest := 0. ^super init ]
Recall that the parent took care of the new
message, and
created a new object of the appropriate size. After creation,
the parent also sent an init
message to the new
object. As a subclass of Account, the new object will
receive the init
message first; it sets up its own
instance variable, and then passes the init
message up the
chain to let its parent take care of its part of the
initialization.
With our new Savings
account created, we can define
two methods for dealing specially with such an account:
interest: amount [ interest := interest + amount. self deposit: amount ] clearInterest [ | oldinterest | oldinterest := interest. interest := 0. ^oldinterest ]
We are now finished, and close the class scope:
]
The first method says that we add the amount
to our
running total of interest. The line self deposit: amount
tells Smalltalk to send ourselves a message, in this case
deposit: amount
. This then causes Smalltalk to look up
the method for deposit:
, which it finds in our parent,
Account. Executing this method then updates our overall
balance.28
One may wonder why we don’t just replace this with the
simpler balance := balance + amount
. The answer lies
in one of the philosophies of object-oriented languages in general,
and Smalltalk in particular. Our goal is to encode a
technique for doing something once only, and then re-using
that technique when needed. If we had directly encoded
balance := balance + amount
here, there would have been
two places that knew how to update the balance from a
deposit. This may seem like a useless difference. But consider
if later we decided to start counting the number of
deposits made. If we had encoded
balance := balance + amount
in each place that needed to
update the balance, we would have to hunt each of them down in
order to update the count of deposits. By sending self
the message deposit:
, we need only update this method
once; each sender of this message would then automatically get the correct
up-to-date technique for updating the balance.
The second method, clearInterest
, is simpler. We
create a temporary variable oldinterest
to hold the current
amount of interest. We then zero out our interest to
start the year afresh. Finally, we return the old interest
as our result, so that our year-end accountant can see how
much we made.29
self
is much like super
, except that
self
will start looking for a method at the bottom
of the type hierarchy for the object, while
super
starts looking one level up from the current
level. Thus, using super
forces inheritance,
but self
will find the first definition
of the message which it can.
Of course, in a real accounting system we would never discard such information—we’d probably throw it into a Dictionary object, indexed by the year that we’re finishing. The ambitious might want to try their hand at implementing such an enhancement.
Next: The Checking class, Up: Creating subclasses