Skip to content

Instantly share code, notes, and snippets.

@j5ik2o
Last active October 24, 2019 06:19
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save j5ik2o/11d1f9c83b83af97fecbc6713665a72f to your computer and use it in GitHub Desktop.
Save j5ik2o/11d1f9c83b83af97fecbc6713665a72f to your computer and use it in GitHub Desktop.

Lean Architecture APPENDIX A, ScalaでのDCIサンプルです。コプリエンさん作です。

increaseBalanceUnitを返すとはないわ〜。(今どき可変オブジェクトを中心にドメインを考えたくないという意味で。多分こういう考え方の人は関数型勢に多い。

import java.time.Instant // 元のサンプルはjava.util.Dateだったがさすがにそれは辞めろ的な意味で書き換えた

// Data
trait Account {
  protected var balance: Long = 0

  def availableBalance: Long = balance
  
  // Unitを返すのは避けたい
  def decreaseBalance(amount: Long): Unit = {
    require(amount >= 0)
    balance -= amount
  }

  // Unitを返すのは避けたい
  def increaseBalance(amount: Long): Unit = 
    balance += amount

  // ↓ こういうのもドメインの外側でやるべきでしょう
  def updateLong(msg: String, date: Instant, amount: Long): Unit = 
    println(s"Account $toString, $msg, $date, $amount")

}

// Methodless Role
trait MoneySink {
  def increaseBalance(amount: Long): Unit
  def updateLong(msg: String, date: Instant, amount: Long): Unit
}

trait MoneySource {
  def transferTo(amount: Long, recipient: MoneySink): Unit
}

// Methodfull Role
trait TransferMoneySink extends MoneySink { this: Account =>
  def transferFrom(amount: Long, src: MoneySource): Unit = {
    increaseBalance(amount)
    updateLong("Transfer in", Instant.now(), amount)
  }
}

trait TransferMoneySource extends MoneySource {
  this: Account =>
  override def transferTo(amount: Long, recipient: MoneySink): Unit = {
    decreaseBalance(amount)
    recipient.increaseBalance(amount)
    updateLong("Transfer out", Instant.now(), amount)
    recipient.updateLong("Transfer In", Instant.now(), amount)
  }
}

class SavingsAccount extends Account {
  override def toString: String = "Savings"
}

class CheckingAccount extends Account {
  override def toString: String = "Check"
}

// Context
object Main extends App {
  val source = new SavingsAccount with TransferMoneySource
  val sink = new CheckingAccount with TransferMoneySink
  source.increaseBalance(100000)
  source.transferTo(200, sink)
  println(source.availableBalance + ", " + sink.availableBalance)

}

さて、こう書けるようにするにはどうしたらよいのだ…。

object Main extends App {
  val source = new SavingsAccount with TransferMoneySource
  val sink = new CheckingAccount with TransferMoneySink
  val newSource1: Account with MoneySource = source.increaseBalance(100000)
  val result: (Account with MoneySource, Account with MoneySink) = newSource1.transferTo(200, sink)
  println(result._1.availableBalance + ", " + result._2.availableBalance)
}

DCIがわからんという人は以下参照してください。

https://digitalsoul.hatenadiary.org/entry/20100131/1264925022

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment