Composing a new type that contains an existing type

As part of a new initiative, the bank wants us to support a new savings account product, which provides daily interest for customers. Since the existing account management's functionality is critical to the bank's business and is maintained by a different team, we have decided to reuse its functionality without touching any of the existing source code.

First, let's create our own SavingsAccount data type, as follows:

struct SavingsAccount
acct::Account
interest_rate::Float64

SavingsAccount(account_number, balance, date_opened, interest_rate) = new(
Account(account_number, balance, date_opened),
interest_rate
)
end

The first field, acct, is used to hold an Account object, while the second field, interest_rate, contains the interest rate per annum for the account. A constructor is also defined to instantiate the object.

In order to use the underlying Account object, we can use a technique called Delegation, or Method Forwarding. This is where we implement the same API in SavingsAccount and forward the call to the underlying Account object whenever we want to reuse the existing functions from the underlying object. In this case, we can just forward all the field accessor functions and mutating functions from the Account object, as follows:

# Forward assessors
account_number(sa::SavingsAccount) = account_number(sa.acct)
balance(sa::SavingsAccount) = balance(sa.acct)
date_opened(sa::SavingsAccount) = date_opened(sa.acct)

# Forward methods
deposit!(sa::SavingsAccount, amount::Real) = deposit!(sa.acct, amount)

withdraw!(sa::SavingsAccount, amount::Real) = withdraw!(sa.acct, amount)

transfer!(sa1::SavingsAccount, sa2::SavingsAccount, amount::Real) = transfer!(
sa1.acct, sa2.acct, amount)

So far, we have successfully reused the Account data type, but let's not forget that we actually want to build new features in the first place. A savings account should accrue interest overnight on a daily basis. So, for the SavingsAccount object, we can implement a new accessor for the interest_rate field and a new mutating function called accrue_daily_interest!:

# new accessor
interest_rate(sa::SavingsAccount) = sa.interest_rate

# new behavior
function accrue_daily_interest!(sa::SavingsAccount)
interest = balance(sa.acct) * interest_rate(sa) / 365
deposit!(sa.acct, interest)
end

At this time, we have created a new SavingsAccount object that works just like the original Account object, except it has the additional capability of accruing interest!

However, the sheer volume of these forwarding methods makes us feel a little unsatisfied. It would be nice if we didn't have to write all this code manually. Perhaps there's a better way...

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.133.144.197