rendered paste body#!/usr/bin/env fan
mixin Actor
{
abstract Role actAs(Type role)
}
mixin Role
{
abstract Role apply(Actor actor)
}
class Account : Actor
{
readonly Decimal balance
new make(Decimal balance := 0d) { this.balance = balance }
override Role actAs(Type role)
{
try
{
return ((Role)role.make).apply(this)
} catch (Err e)
{
throw Err("illegal argument", e)
}
}
Void deposit(Decimal amount)
{
balance += amount
}
Void withdraw(Decimal amount)
{
balance -= amount
}
}
mixin MoneySource : Role
{
abstract Void withdraw(Decimal amount)
}
mixin MoneySink : Role
{
abstract Void deposit(Decimal amount)
}
class TransferMoneySource : MoneySource
{
Account? account
new make(Actor? actor := null) { account = actor }
override Role apply(Actor actor)
{
return TransferMoneySource(actor)
}
Void transfer(Decimal amount, MoneySink to)
{
withdraw(amount)
to.deposit(amount)
}
override Void withdraw(Decimal amount)
{
account?.withdraw(amount)
}
}
class TransferMoneySink : MoneySink
{
Account? account
new make(Actor? actor := null) { account = actor }
override Role apply(Actor actor)
{
return TransferMoneySink(actor)
}
Void transfer(Decimal amount, MoneySource from)
{
from.withdraw(amount)
deposit(amount)
}
override Void deposit(Decimal amount)
{
account?.deposit(amount)
}
}
mixin UseCase
{
abstract Void execute()
}
class WithDrawal : UseCase
{
Account savingsAccount
Account investmentAccount
Decimal amount
new make(Account savingsAccount, Account investmentAccount, Decimal amount)
{
this.savingsAccount = savingsAccount
this.investmentAccount = investmentAccount
this.amount = amount
}
override Void execute()
{
source := (TransferMoneySource) savingsAccount.actAs(TransferMoneySource#)
sink := (TransferMoneySink) investmentAccount.actAs(TransferMoneySink#)
source.transfer(amount, sink)
}
}
class Deposit : UseCase
{
Account savingsAccount
Account investmentAccount
Decimal amount
new make(Account savingsAccount, Account investmentAccount, Decimal amount)
{
this.savingsAccount = savingsAccount
this.investmentAccount = investmentAccount
this.amount = amount
}
override Void execute()
{
source := (TransferMoneySource) investmentAccount.actAs(TransferMoneySource#)
sink := (TransferMoneySink) savingsAccount.actAs(TransferMoneySink#)
source.transfer(amount, sink)
}
}
class Main
{
static Void main()
{
srcAccount := Account(100d)
dstAccount := Account(200d)
echo("srcAccount.balance=${srcAccount.balance}")
echo("dstAccount.balance=${dstAccount.balance}")
WithDrawal(srcAccount, dstAccount, 50d).execute
echo("----------------------------------------")
echo("srcAccount.balance=${srcAccount.balance}")
echo("dstAccount.balance=${dstAccount.balance}")
Deposit(srcAccount, dstAccount, 100d).execute
echo("----------------------------------------")
echo("srcAccount.balance=${srcAccount.balance}")
echo("dstAccount.balance=${dstAccount.balance}")
}
}