2012-11-17 209 views
3

我最近開始學習Scala,並開始創建一個簡單的roguelike遊戲的小項目。然而,我堅持試圖實現觀察者模式。 This答案觸及了這個問題,但我無法弄清楚如何使它工作。以下是上面鏈接的答案中的代碼。我大多對「this:S =>」部分代碼感到困惑,我想我應該有某種功能,但我不確定。我想讓它從類中返回一個元組來擴展主題特徵。實現觀察者模式

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)) 
} 

回答

9

有關self類型和另一個代碼示例,請參閱Steve的回答。

這是一些使用觀察者的示例代碼。 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 = [email protected] 

scala> val ar = new AccountReporter 
ar: AccountReporter = [email protected] 

scala> oa.addObserver(ar) 

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

scala> oa.withdraw(40.0) 
Observed balance change: 100.0 
+0

感謝您的具體例子。現在工作得很好。 – Zavior

1

這是一個Scala的自類型(見http://www.scala-lang.org/node/124)。它表達了一個要求,即特質Subject [S]的所有具體實現都必須符合S類型。也就是說,每個可觀察的Subject [S]本身都是S.這對Observer模式是合理的 - 它是可觀察主體本身應該有註冊和通知方法,所以與S觀察員一致的主題本身應該是S.

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 AccountReporter { 
    def receiveUpdate(account: Account) = 
     println("Observed balance change: "+account.balance) 
} 

... 
observedAccount.addObserver(accountReporter.receiveUpdate _)