" DCI program: BB5aBank "

" Exported from Squeak 7179-basic.76.image on: 18 December 2011 by: Trygve "

" Data perspective "

" Class BB5aBank "

" The Bank functionality is here to manage a number of accounts named by their account number.
The Bank instance is created with some accounts and their balance.

Instance variables:
    accounts (Dictionary accountName -> accountObject)
    traceWindow (BB2TraceHolder) For displaying the result of the test.


See BB5Testing for more information. "

Object subclass: #BB5aBank
    instanceVariableNames: 'accounts traceWindow'
    classVariableNames: ''
    poolDictionaries: ''
    category: 'BB5aBank-Data'

" BB5aBank instance methods in category: access "

addCheckingAccountNumbered: aNumber
    ^accounts at: aNumber put: BB5aCheckingAccount new.

addSavingsAccountNumbered: aNumber
    ^accounts at: aNumber put: BB5aSavingsAccount new.

findAccount: accountNumber
    ^accounts at: accountNumber ifAbsent: [nil]

" BB5aBank instance methods in category: private "

initialize
    super initialize.
    accounts := Dictionary new.

" Class BB5aCheckingAccount "

" Instances are bank accounts of a special kind. (CheckingAccount and SavingaAccount are here actually equal. We use two different Account classes to illustrate that a role may be played by instances of different classes).

Instance vaiables:
    balance (Integer) the current balance.
    
See Testing>BB5Testing for more information. "

Object subclass: #BB5aCheckingAccount
    instanceVariableNames: 'balance'
    classVariableNames: ''
    poolDictionaries: ''
    category: 'BB5aBank-Data'

" BB5aCheckingAccount instance methods in category: access "

balance
    ^balance

decrease: amount
    balance := balance - amount.

increase: amount
    balance := balance + amount.

" BB5aCheckingAccount instance methods in category: private "

initialize
    balance := 0.

" BB5aCheckingAccount instance methods in category: role methods "

deposit: amount
    self increase: amount.

" Class BB5aSavingsAccount "

" Instances are bank accounts of a special kind. (CheckingAccount and SavingaAccount are here actually equal. We use two different Account classes to illustrate that a role may be played by instances of different classes).

Instance vaiables:
    balance (Integer) the current balance.
    
See Testing>BB5Testing for more information. "

Object subclass: #BB5aSavingsAccount
    instanceVariableNames: 'balance'
    classVariableNames: ''
    poolDictionaries: ''
    category: 'BB5aBank-Data'

" BB5aSavingsAccount instance methods in category: access "

balance
    ^balance

decrease: amount
    balance := balance - amount.

increase: amount
    balance := balance + amount.

" BB5aSavingsAccount instance methods in category: private "

initialize
    balance := 0.

" BB5aSavingsAccount instance methods in category: role methods "

deposit: amount
"self doOnlyOnce: [self halt]." "self rearmOneShot"
    self increase: amount.

" Context perspective "

" Context: BB5aMoneyTransferContext "

" Class BB5aMoneyTransferContext "

" This Context performs the transfer funds system operation.

Instance variables:
    bank (Bank) The transfer is between accounts within the same bank.
    fromAccountNumber (Object)
    toAccountNumber (Object)
    
See Testing>BB5Testing for more information. "

BB1Context subclass: #BB5aMoneyTransferContext
    instanceVariableNames: 'bank fromAccountNumber toAccountNumber amount'
    classVariableNames: ''
    poolDictionaries: ''
    category: 'BB5aBank-Context'

" BB5aMoneyTransferContext instance methods in category: access "

bank: bnk
    bank := bnk.

fromAccountNumber: aFromNumber
    fromAccountNumber := aFromNumber.

toAccountNumber: aToNumber
    toAccountNumber := aToNumber.

" BB5aMoneyTransferContext instance methods in category: role binding "

Amount
    ^amount

TransferMoneySink
    ^bank findAccount: toAccountNumber

TransferMoneySource
    ^bank findAccount: fromAccountNumber

" BB5aMoneyTransferContext instance methods in category: triggers "

transfer: amnt fromAccountNumber: from toAccountNumber: to inBank: bnk
    bank := bnk.
    fromAccountNumber := from.
    toAccountNumber := to.
    amount := amnt.
    self runInteractionFromRoleNamed: #TransferMoneySource.

" BB5aMoneyTransferContext class class methods in category: context diagram "

linkBreakPoints
    | dict |
    (dict := Dictionary new)
        yourself.
    ^dict.

rolePositions
    | dict |
    (dict := Dictionary new)
        at: #TransferMoneySource put: 20@15;
        at: #TransferMoneySink put: 320@85;
        at: #Amount put: 168@178;
        yourself.
    ^dict.

" BB5aMoneyTransferContext class class methods in category: role structure "

roleStructure
    ^super roleStructure
    at: #TransferMoneySource put: #(#Amount #TransferMoneySink );
    at: #TransferMoneySink put: #(#Amount );
    at: #Amount put: #();
        yourself.

No diagram

" Methodless Role Amount "

" Methodful Role TransferMoneySink "

deposit
    self increase: Amount.

" Methodful Role TransferMoneySource "

transfer
    TransferMoneySource withdraw: Amount.
    TransferMoneySink deposit.

run
    TransferMoneySource transfer.

withdraw: amount
    self balance < amount ifTrue: [self notify: 'Insufficient funds'. ^self].
    self decrease: amount.


" Testing perspective "

" Class BB5aTesting "

" The BB5Bank example implements a simple transfer of funds from one bank account to another.
There is a single test realized by the class (meta) side of this BB5Testing class.

The test results are shown in a special Workspace. "

Object subclass: #BB5aTesting
    instanceVariableNames: ''
    classVariableNames: ''
    poolDictionaries: ''
    category: 'BB5aBank-Testing'

" BB5aTesting class class methods in category: class initialization "

initialize
    " BB5aTesting initialize "
    TheWorldMenu unregisterOpenCommand: 'BB5b: Bank transfer'.
    TheWorldMenu
        registerOpenCommand:
            {'BB5a: Bank transfer'. { BB5aTesting. #test1. }. 'Transfer funds from one account to another'}.

" BB5aTesting class class methods in category: tests "

test1
    " BB5aTesting test1 "
    | bank |
    bank := BB5aBank new.
    (bank addCheckingAccountNumbered: 1111) increase: 2000.
    bank addSavingsAccountNumbered: 2222.
    self assert:
            [(bank findAccount: 1111) balance = 2000.
            (bank findAccount: 2222) balance = 0].
    BB5aMoneyTransferContext new
        transfer: 500 fromAccountNumber: 1111 toAccountNumber: 2222 inBank: bank.
    self assert:
            [(bank findAccount: 1111) balance = 1500.
            (bank findAccount: 2222) balance = 500].
    self inform: 'Test OK'.