Skip to content

Instantly share code, notes, and snippets.

@j5ik2o j5ik2o/DCI.md
Last active Oct 24, 2019

Embed
What would you like to do?

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
You can’t perform that action at this time.