Introduction
ObjectTeams/Java (OT/J) is an extension to Java programming language that facilitates roles and collaborations as the first class language constructs. This article is an exercise on using (OT/J) for implementing collaborations.
Subject area
This exercise considers two bank operations – money transfer and fund cashing. The course of events for these two operations is very similar in basic and differs in details. Considering this, it is implemented as an abstract withdraw routine leaving detail differences to concrete implementations.
An abstract withdraw routine
Figure 1 |
A withdraw routine executed in a bank allows to move funds from one account to another. The bank, which executes this operation, charges some fee, applied to the credit account and debited onto the bank’s operational account. When the currency of the operation is not the same as the bank’s native currency, the bank converts the fee to the native currency.
A collaboration diagram for this operation is given on Figure 1. The collaboration steps and reiterated below:
- Calculate a fee for this operation
- Charge the amount+fee from the credit account
- Put the money on the debit account, which is expected to accept any currency
- If the currency of the operation differs from the currency of the banks’ operational account conversion is applied to the fee
- Put the fee is on the operational account
A function that implements this code is given below (for a complete class please refer to the source):
protected final void withdraw(BigDecimal amount, CreditAccount creditAccount, DebitAccount debitAccount, OperationalAccount operationalAccount, CurrencyConverter currencyConvertor) { BigDecimal fee = calculateFee(amount); creditAccount.credit(amount.add(fee)); debitAccount.debit(amount,creditAccount.currency()); if( creditAccount.currency() != operationalAccount.currency()) fee = currencyConvertor.convert(creditAccount.currency(), operationalAccount.currency(), fee); operationalAccount.debit(fee); }
In this exercise, this method is implemented in scope of a team class Withdraw Collaboration and the parameter types are defined as role classes in the team. This class is pretty isolated and depends only on Currency class, so it can be reused in other applications. Details of the account implementations are hidden behind the roles.
Concrete withdrawal routines
A bank that implements concrete withdrawal routines, gives its clients two interfaces – the Cashier interface that allows people to get some cash from they accounts, and the Wire Operator interface that allows them to transfer funds from the account they have in this bank to any other account. In scope of this exercise, these two interfaces are implemented by two collaboration, both extending the Withdraw Collaboration. Each collaboration is instantiated in the bank for a given account and then returned to the client. Once the interface is provided, the client may execute more than one operation with the current account.
Since there could be a rather long thinking time, the bank can not provide an operational account at the time when the interface is acquired, but instead the operation account should be determined at the moment of transaction execution. To achieve this, these collaborations are extended with an additional role – Operator which provides access to the available operational account at the moment of transaction execution.
Additional complications with implementing the Cashier that there is not debit account available, since the money are given to a person and the person cannot accept a decimal value, he/she can only take cash, so the digits should be converted to cash. Code snippet for this operation is given below (for a complete class please refer to the source):
public void giveCashTo(Person person, double amount) { BigDecimal value = new BigDecimal(amount); reserved = bank.acquireCash(value, account.currency()); try { cashOperation(new BigDecimal(amount), account, person, bank, bank); } finally { if( reserved.value().signum() != 0 ) { // Recipient did not take the money bank.returnCash(reserved); } } }
To match the Person entity with the DebitAccount interface, a new role is defined as below:
protected class CashRecipient extends DebitAccount playedBy Person { void takes(Cash cash) -> void takes(Cash cash); protected void debit(BigDecimal amount, Currency currency) { assert reserved.value() == amount && reserved.currency() == currency; takes(reserved); } }
Bank
In this exercise a bank has an internal operational account, and a safe, where all cash is kept. It provides methods for opening accounts (credit and current) and access to two already mentioned interfaces Cashier and Wire Operator. BankAccount is an protected inner class of the Bank to ensure that no one can create a bank account outside of a bank (for a complete class please refer to the source).
Cash
If everyone would be able to create cash in their own, there would be no need for banks and accounts :). Also, when cash is being added or subtracted, its behavior differs very much from adding two numbers. To model these features of the cash, a dedicated class is provided. The only public constructor it provides creates zero cash. The add operation accepts Cash as the addendum and clears it after adding. The subtract operation accepts a number and creates a new cash for the amount of subtrahend. Also it provides an instruction to the garbage collector to report any occurrence of valuable cash in the garbage (for a complete class please refer to the source).
Modeling the plan
With the mentioned above classes (and some additional) we can now model Tom and Mary’s plan:
Entities that are assumed to exist:
Bank spicer = new Bank("JVM-Spicer,MN ", Currency.USD); Bank willmar = new Bank("OTJ-Willmar,MN", Currency.EUR); Bank bahama = new Bank("Java-Bahamas ", Currency.BSD); Person tom = new Person("Tom "); Person mary = new Person("Mary");
The plan:
Account credit = spicer.openCreditAccount(1000000, Currency.USD); Cashier cashier = spicer.cashier(credit); cashier.giveCashTo(tom, 970000); mary.takes( tom.gives(965000, Currency.USD) ); Account deposit = willmar.openAccount(mary.gives(960000,Currency.USD)); Account bahamamama = bahama.openAccount(mary.gives(1000,Currency.USD)); WireTransfer wire = willmar.wireOperator(deposit); wire.wireTo(bahamamama, 950000); cashier = bahama.cashier(bahamamama); cashier.giveCashTo(mary, 923000); tom.takes( mary.gives(461000, Currency.USD) );
All sources are available for downloading as a single archive under The GNU Lesser General Public License (LGPLv3).
Conclusion
Collaboration design pattern is a useful abstraction for designing the application. Implementing collaborations with a new, promising Java language extension facilitates using of the first class language constructs (teams) and significantly improves the separation of concerns letting the developer to concentrate on one task at a time.
Post a Comment