projection: Context-Classes
Class: BB5aMoneyTransferCTX
BB1Context subclass: #BB5aMoneyTransferCTX
instanceVariableNames: 'transaction'
category: 'BB5aBank-Context'
" This is a very simple example where a user operates an automatic teller machine to transfer money from one bank account to another.
Bankers know that accounts actually exist as a summation of transaction records in the General Ledger transction collection. The accounts in this example are to be understood as caches on the Ledger.
Version a (this version) ignores the Ledger for the sake of simplicity.
Version b is more correct in that includes the Ledger with its transaction records. "
instanceMethods: role binding
AMOUNT
^transaction amount
DESTINATIONACCOUNT
^ transaction toAccount
SOURCEACCOUNT
^transaction fromAccount
instanceMethods: system operations
transferTransaction: transact
transaction := transact.
^ self triggerInteractionFrom: #SOURCEACCOUNT with: #transferTo.
projection: BB5aMoneyTransferCTX-Interaction
roleMethods: DESTINATIONACCOUNT
transferFrom
self increase: AMOUNT.
^true
roleMethods: SOURCEACCOUNT
transferTo
SOURCEACCOUNT balance >= AMOUNT
ifTrue:
[self decrease: AMOUNT.
^DESTINATIONACCOUNT transferFrom]
ifFalse:
[self inform: 'Error. Insufficient funds'.
^false]
projection: Data-classes
Class: BB5aAccount
Object subclass: #BB5aAccount
instanceVariableNames: 'balance'
category: 'BB5aBank-Data'
" An Account object is a cache on the Ledger transactions. "
instanceMethods: initialize-release
initialize
balance := 0.
instanceMethods: attributes-read
balance
^balance
instanceMethods: operations
increase: amount
balance := balance + amount.
decrease: amount
balance := balance - amount.
Class: BB5aBank
Object subclass: #BB5aBank
instanceVariableNames: 'transactions accounts bank'
category: 'BB5aBank-Data'
instanceMethods: initialize-release
initialize
super initialize.
accounts := Dictionary new.
transactions := OrderedCollection new.
instanceMethods: attributes-read
findAccountNo: accountNumber
^accounts at: accountNumber ifAbsent: [nil]
transactions
^transactions
instanceMethods: operations
addAccountNo: aNumber
^accounts at: aNumber put: BB5aAccount new.
addTransaction: trans
transactions add: trans.
Class: BB5aTransaction
Object subclass: #BB5aTransaction
instanceVariableNames: 'bank date amount fromAccNo toAccNo'
category: 'BB5aBank-Data'
instanceMethods: initialize
bank: bnk amount: amt from: from to: to
bank := bnk.
date := Time dateAndTimeNow.
amount := amt.
fromAccNo := from.
toAccNo := to.
instanceMethods: accessing
amount
^ amount
bank
^ bank
date
^ date
fromAccount
^bank findAccountNo: fromAccNo
toAccount
^bank findAccountNo: toAccNo
projection: Testing-classes
Class: BB5aTesting
Object subclass: #BB5aTesting
instanceVariableNames: 'bank account1 account2'
category: 'BB5aBank-Testing'
" See comment in Context >> BB5aMoneyTransferContext "
instanceMethods: operations
test
" BB5aTesting test "
bank := BB5aBank new.
account1 := bank addAccountNo: 1111.
account2 := bank addAccountNo: 2222.
self test1.
self test2.
test1
| transaction1 |
account1 increase: 2000.
self assert:
[account1 balance = 2000 &
account2 balance = 0].
transaction1 := BB5aTransaction new bank: bank amount: 500 from: 1111 to: 2222.
(BB5aMoneyTransferCTX new transferTransaction: transaction1)
ifTrue:
[self assert:
[(bank findAccountNo: 1111) balance = 1500 &
(bank findAccountNo: 2222) balance = 500].
self inform: 'Test1 OK' , String cr , 'Close this box and get error: Insuffucient funds.'.]
ifFalse:
[self inform: 'Test1 failure'].
test2
| transaction2 |
self assert:
[account1 balance = 1500 &
account2 balance = 500].
transaction2 := BB5aTransaction new bank: bank amount: 5000 from: 1111 to: 2222.
(BB5aMoneyTransferCTX new transferTransaction: transaction2)
ifTrue:
[self assert:
[(bank transactions size > 0 and: [bank transactions last == transaction2])&
(bank findAccountNo: 1111) balance = 1000 &
(bank findAccountNo: 2222) balance = 1000]
descriptionBlock: [self inform: 'Test2 OK, it has failed as expected!']]
ifFalse:
[self inform: 'Test2 OK, it has failed as expected!'].
classMethods: tests
test
" BB5aTesting test "
self new test.