All pastes #1912516 Raw Edit

katox

public text v1 · immutable
#1912516 ·published 2010-08-06 22:42 UTC
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}")

  }
}