3

我最近开始学习 Scala 并开始了一个小项目来创建一个简单的 roguelike 游戏。但是,我一直在尝试实现观察者模式。 这个答案触及了主题,但我不知道如何让它发挥作用。以下是上面链接的答案中的代码。我对代码中的“ this: S => ”部分感到困惑,我想我应该在那里有某种函数,但我不确定。我想让它从将扩展 Subject 特征的类中返回一个元组。

trait Observer[S] {
 def receiveUpdate(subject: S);
}

trait Subject[S] {
 this: S =>
 private var observers: List[Observer[S]] = Nil
 def addObserver(observer: Observer[S]) = observers = observer :: observers

 def notifyObservers() = observers.foreach(_.receiveUpdate(this))
}
4

4 回答 4

10

请参阅史蒂夫关于类型的回答self和另一个代码示例。

这是一些使用观察者的示例代码。ObservedAccount是观察者Subject观察到的AccountReporter

trait Observer[S] {
    def receiveUpdate(subject: S);
}

trait Subject[S] { 
    this: S =>
    private var observers: List[Observer[S]] = Nil
    def addObserver(observer: Observer[S]) = observers = observer :: observers

    def notifyObservers() = observers.foreach(_.receiveUpdate(this))
}

class Account(initialBalance: Double) {
    private var currentBalance = initialBalance
    def balance = currentBalance
    def deposit(amount: Double)  = currentBalance += amount
    def withdraw(amount: Double) = currentBalance -= amount
}

class ObservedAccount(initialBalance: Double) extends Account(initialBalance) with Subject[Account] {
    override def deposit(amount: Double) = {
        super.deposit(amount)
        notifyObservers()
    }
    override def withdraw(amount: Double) = {
        super.withdraw(amount)
        notifyObservers()
    }
}


class AccountReporter extends Observer[Account] {
    def receiveUpdate(account: Account) =
        println("Observed balance change: "+account.balance)
}

让我们看看它的实际效果:

scala> val oa = new ObservedAccount(100.0)
oa: ObservedAccount = ObservedAccount@3f947e20

scala> val ar = new AccountReporter
ar: AccountReporter = AccountReporter@6ea70a98

scala> oa.addObserver(ar)

scala> oa.deposit(40.0)
Observed balance change: 140.0

scala> oa.withdraw(40.0)
Observed balance change: 100.0
于 2012-11-18T06:57:50.650 回答
3

以布赖恩的回答为基础:我发现没有必要有一个单独的Observer[S]特征,就S => Unit足够了:

trait Subject[S] {
  this: S =>
  private var observers: List[S => Unit] = Nil
  def addObserver(observer: S => Unit) = observers = observer :: observers
  def notifyObservers() = observers.foreach(_.apply(this))
}

class Account(initialBalance: Double) {
  private var currentBalance = initialBalance
  def balance = currentBalance
  def deposit(amount: Double) = currentBalance += amount
  def withdraw(amount: Double) = currentBalance -= amount
}

class ObservedAccount(initialBalance: Double) extends Account(initialBalance)
  with Subject[Account] {

  override def deposit(amount: Double) = {
    super.deposit(amount)
    notifyObservers()
  }
  override def withdraw(amount: Double) = {
    super.withdraw(amount)
    notifyObservers()
  }
}

class AccountReporter {
  def receiveUpdate(account: Account) =
    println("Observed balance change: " + account.balance)
}

object Main extends App {
  println("start app")
  val oa = new ObservedAccount(100.0)
  val ar = new AccountReporter
  oa.addObserver(ar.receiveUpdate _)
  oa.deposit(40.0)
  oa.deposit(60.0)
  println("stop  app")
}


/**
      a copy paste observer pattern scala mini-app
      sbt run should produce:
      [info] Running app.Main
      start app
      Observed balance change: 140.0
      Observed balance change: 200.0
      stop  app
  */
于 2012-11-19T10:11:41.133 回答
2

很抱歉用问题来回答问题。您是否在这里阅读过答案更有趣的答案?有人应该编制一个阅读清单,如果他们没有。Coursera 有阅读清单吗?

于 2012-11-18T01:58:03.253 回答
1

这是一个 Scala 自类型(参见http://www.scala-lang.org/node/124)。它表达了一个要求,即特征 Subject[S] 的所有具体实现也必须符合类型 S。也就是说,每个可观察的 Subject[S] 本身就是一个 S。

这对于观察者模式来说是合理的——它是可观察的主体本身应该具有注册和通知方法,因此与 S 的观察者一致的主体应该本身就是一个 S。

于 2012-11-17T22:20:51.427 回答