【问题标题】:Implementing observer pattern实现观察者模式
【发布时间】:2012-11-17 21:54:29
【问题描述】:

我最近开始学习 Scala 并开始了一个小项目来创建一个简单的 roguelike 游戏。但是,我一直在尝试实现观察者模式。 This 回答触及主题,但我不知道如何使其发挥作用。以下是上面链接的答案中的代码。我对代码的“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))
}

【问题讨论】:

    标签: scala


    【解决方案1】:

    请参阅 Steve 对 self 类型的回答以及另一个代码示例。

    这是一些使用观察者的示例代码。 ObservedAccount 是由AccountReporter 观察者观察到的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))
    }
    
    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
    

    【讨论】:

      【解决方案2】:

      基于 Brian 的回答:我发现没有必要拥有单独的 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
        */
      

      【讨论】:

        【解决方案3】:

        很抱歉用问题来回答问题。你读过your answer herethe more interesting answer herehere吗?有人应该编制一个阅读清单,如果他们没有。 Coursera 有阅读清单吗?

        【讨论】:

        • 我确实看了看,但决定暂时不尝试对我来说全新的东西:)
        【解决方案4】:

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

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

        【讨论】:

          猜你喜欢
          • 2011-12-21
          • 1970-01-01
          • 1970-01-01
          • 2015-02-12
          • 2013-10-28
          • 1970-01-01
          • 2012-05-11
          • 2015-01-30
          • 2017-01-23
          相关资源
          最近更新 更多