Section 1: Polymorphism Example
- Suppose a set of account classes such as
CheckingAccount
andSavingsAccount
are derived from superclassAccount
. - In object-oriented programming, each of these classes might be endowed with the
ability to
closeMonth()
. - Although each class has its own
closeMonth()
method, thecloseMonth()
method for each account is quite different. - When performing end-of-month tasks, whatever the account may be,
it would be nice to be able to treat all of the accounts generically as objects of the superclass
Account
. - Then to perform any monthly account tasks, we could simply call method
closeMonth()
of superclassAccount
and let the program determine dynamically (that is, at execution time) which subclasscloseMonth()
method to use. - To enable this kind of behavior, we declare
closeMonth()
in the superclass, and then we overridecloseMonth()
in each of the subclasses to handle end of month. - In the subclass
CheckingAccount
, thecloseMonth()
method would levy a charge of $25 for any overdrawn accounts, or a charge of $4 for any account whose balance has dropped below $2500. - In the subclass
SavingsAccount
, thecloseMonth()
method levy a charge of $35 for any overdrawn accounts, or otherwise calculate interest earned. - Each close of month activity, however, is initiated by a call to the
closeMonth()
method associated with the superclassAccount
, and the proper action is determined dynamically, depending on the type of account. - To test this behavior, we declare an array that holds an object of type
CheckingAccount
and an object of typeSavingsAccount
. - Then we direct each array item to
closeMonth()
, and the end-of-month calculations are performed correctly, based on the type of account.
// Account class - the base class
class Account {
#balance;
constructor(startBalance) {
this.#balance = startBalance;
}
set balance(value) {
this.#balance = value;
}
get balance() {
return this.#balance;
}
closeMonth() {}
}
// derived class CheckingAccount - overrides closeMonth method to handle checking fees
class CheckingAccount extends Account {
// This overrides the base class method.
closeMonth() {
if (super.balance < 0) {
// If balance is negative, apply a $25 charge
super.balance = super.balance() - 25;
}
else if (super.balance < 2500) {
// If balance is less than 2500, then apply monthly charge
super.balance = (super.balance - 4);
}
}
}
// derived class SavingsAccount - overrides closeMonth method to handle savings fees
class SavingsAccount extends Account {
get interest() {
return this.#interestRate;
}
set interest(value) {
this.#interestRate = value;
}
// This overrides the base class method.
closeMonth() {
if (super.balance < 0) {
// If balance is negative, apply a $35 charge
super.balance = super.balance() - 35;
}
else {
// apply an interest equal to that stored in the interestRate variable
super.balance = (super.balance * (1 + this.#interestRate));
}
}
}
function test() {
let acct1 = new CheckingAccount();
acct1.balance = 1200;
alert("The checking balance for acct1 is initially " + acct1.balance);
acct1.closeMonth();
alert("The end-of-month checking balance for acct1 is " + acct1.balance);
let acct2 = new SavingsAccount(7600);
alert("The savings balance for acct2 is initially " + acct2.balance);
acct2.closeMonth();
alert("The end-of-month savings balance for acct2 is " + acct2.balance);
alert("*** Moving to array of objects ***");
let acctList = [acct1, acct2];
acctList[0].closeMonth();
alert("The end-of-month " + getType(acctList[0]) + " balance for acctList[0] is " + acctList[0].balance);
acctList[1].closeMonth();
alert("The end-of-month " + getType(acctList[1]) + " balance for acctList[1] is " + acctList[1].balance);
}
function getType(clsObject) {
var acctType;
if (clsObject instanceof CheckingAccount) {
acctType = "checking";
}
else {
acctType = "savings";
}
return acctType
}