Last active
November 4, 2024 05:00
-
-
Save mbrowne/36d17f932d0c61f0b575526c39398ce8 to your computer and use it in GitHub Desktop.
DCI in Swift - simple money transfer example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//TransferMoney context | |
class TransferMoney: Context { | |
private let SourceAccount: SourceAccountRole | |
private let DestinationAccount: DestinationAccountRole | |
init(source:AccountData, destination:AccountData) { | |
SourceAccount = source as! SourceAccountRole | |
DestinationAccount = destination as! DestinationAccountRole | |
} | |
func transfer(amount:Int) { | |
SourceAccount.transferFrom(amount) | |
} | |
//note that we cast to base Role protocol so roles methods aren't accessible | |
//outside the Context by default | |
func getDestinationAccount() -> Role { | |
return DestinationAccount | |
} | |
} | |
protocol SourceAccountRole: Role { | |
func transferFrom(amt: Int) | |
//requires: | |
func decreaseBalance(amt: Int) | |
} | |
extension SourceAccountRole { | |
func transferFrom(amt: Int) { | |
decreaseBalance(amt) | |
DestinationAccount.transferTo(amt) | |
} | |
private var DestinationAccount: DestinationAccountRole { | |
get { | |
return (Context.currentContext as! TransferMoney).getDestinationAccount() as! DestinationAccountRole | |
} | |
} | |
} | |
protocol DestinationAccountRole: Role { | |
func transferTo(amt: Int) | |
//requires: | |
func increaseBalance(amt: Int) | |
} | |
extension DestinationAccountRole { | |
func transferTo(amt: Int) { | |
increaseBalance(amt) | |
} | |
} | |
//end TransferMoney context | |
/////////////////////////// | |
protocol AccountData { | |
var balance: Int {get} | |
func increaseBalance(amt: Int) | |
func decreaseBalance(amt: Int) | |
} | |
class Account: AccountData, SourceAccountRole, DestinationAccountRole { | |
private var _balance = 0 | |
var balance: Int { | |
get {return _balance} | |
} | |
func increaseBalance(amt: Int) { | |
_balance += amt | |
} | |
func decreaseBalance(amt: Int) { | |
_balance -= amt | |
} | |
//Hide the constructor and use a factory method instead so that | |
//new instances are typed as AccountData rather than Account by default. | |
//(The Account type would be able to access role methods from outside the Context.) | |
private init() {} | |
class func create() -> AccountData { | |
return Account() | |
} | |
} | |
//DCI library classes | |
protocol Role {} | |
class Context { | |
private static var _currentContext: Context? | |
private var _parentContext: Context? | |
static var currentContext: Context? { | |
get {return _currentContext} | |
} | |
init() { | |
_parentContext = Context._currentContext | |
Context._currentContext = self | |
} | |
deinit { | |
Context._currentContext = _parentContext | |
} | |
} | |
//Run the use case | |
let src = Account.create() | |
src.increaseBalance(30) | |
let dst = Account.create() | |
dst.increaseBalance(30) | |
TransferMoney(source:src, destination:dst).transfer(10) | |
print("Source balance: ", src.balance) | |
print("Destination balance: ", dst.balance) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment