2011-03-24 77 views
2

這裏是什麼,我想做一個簡單的例子:如何創建具有特徵的基於組件的消息處理系統?

abstract class Message() 
case class FooMessage() extends Message 
case class BarMessage() extends Message 
//... other messages ... 

trait Component 
{ 
    def handleMessage(msg: Message):Unit 
} 

trait ComponentType1 extends Component 
{ 
    abstract override def handleMessage(msg: FooMessage) = { 
    //handle foo, pass it up the chain 
    super.handleMessage(msg) 
    } 

    abstract override def handleMessage(msg: BarMessage) = { 
    //handle bar, pass it up the chain 
    super.handleMessage(msg) 
    } 
} 

//handles some other messages, also might handle the same messages as ComponentType1 
trait ComponentType2 extends Component { .. } 

然後,這些ComponentType s爲混合在的一類,以形成完全由模塊化組件的對象。

我有一堆不同的Message s和一堆不同的Component s。

  • 並非所有組件都處理所有消息類型。
  • 多個組件可以處理相同的消息類型。
    • 即使消息由另一個組件處理,組件消息也會逐級通過組件。
  • 組件可以處理多個消息類型。

的問題是,因爲handleMessageComponent定義爲接受Message,當我嘗試特殊化msg參數它不能算作覆蓋。

我知道一個可能的解決方案是聲明一個大匹配語句的大方法handleMessage,但是我希望在可能的情況下爲每個消息定義一個方法。

+3

我認爲你要麼得到心靈扭曲型兩輪牛車或大比賽。爲什麼你不想使用部分功能?請注意,它們可以使用orElse方法輕鬆組合。 – CheatEx 2011-03-24 22:00:48

+1

@CheatEx:我沒有說什麼不想使用部分函數。你會如何在這裏使用它們? – ryeguy 2011-03-25 00:23:27

+0

有關使用部分函數的示例,請參見下文。 – sourcedelica 2011-03-25 04:20:30

回答

1
trait Message 
class FooMessage extends Message 
class BarMessage extends Message 

trait Component { 
    def handleMessage(msg: Message) {} 
    def handleMessage(msg: FooMessage) {} 
    def handleMessage(msg: BarMessage) {} 
} 

trait ComponentType1 extends Component { 
    override def handleMessage(msg: FooMessage) = println("foo1") 
    override def handleMessage(msg: BarMessage) = println("bar1") 
} 

trait ComponentType2 extends Component { 
    override def handleMessage(msg: BarMessage) = println("bar2") 
} 

object component1and2 extends ComponentType1 with ComponentType2 

component1and2.handleMessage(new FooMessage) 
component1and2.handleMessage(new BarMessage) 

打印

foo1 
bar2 

如果你有某個系統中的所有組件的列表,你可以做

componentList.foreach(c => c.handleMessage(msg)) 

它只是無操作的組件的組件沒有處理味精。

+0

已更新爲包含您添加的mixin內容。 – sourcedelica 2011-03-25 02:52:03

+0

訪問者模式對我的方法有什麼好處?我的方法和實現的缺點是你必須爲基本組件trait中的每個消息類型定義一個空方法。 – ryeguy 2011-03-25 03:13:56

+0

我想我錯過了一些東西。'Component'中有2個方法 - 每個'Message'都有一個方法。這正是我想要避免的。如果我在我的實施中這樣做,它無論如何都會起作用。 – ryeguy 2011-03-25 03:36:32

3

這是一個基於部分功能的解決方案。提示到CheatEx的想法。

trait Message 
class FooMessage extends Message 
class BarMessage extends Message 

abstract class Component { 
    type CPF = PartialFunction[Message, Unit] 

    var pf: CPF = { case _ => } 

    def handleMessage(msg: Message) = pf(msg) 
} 

trait ComponentType1 extends Component { 
    val ct1pf: CPF = { 
    case msg: FooMessage => println("foo1") 
    case msg: BarMessage => println("bar1") 
    } 
    pf = ct1pf orElse pf 
} 

trait ComponentType2 extends Component { 
    val parentPf = pf 
    val ct2pf: CPF = { 
    case msg: 
     BarMessage => println("bar2") 
     parentPf(msg) // cascade 
    } 
    pf = ct2pf orElse pf 
} 

object component1and2 extends ComponentType1 with ComponentType2 

component1and2.handleMessage(new FooMessage) 
component1and2.handleMessage(new BarMessage) 

打印

foo1 
bar2 
bar1 
+0

哦...我寫了幾乎完整的答案。 – CheatEx 2011-03-25 04:23:45

+0

一個注意事項:可以編寫句柄消息,例如'def handleMessage(msg:Message):Unit = if(pf.isDefinedAt(msg))pf(msg)'並避免出現'case _' – CheatEx 2011-03-25 04:30:29

+0

另一個問題。 OP希望消息能夠被處理和級聯。所以,大概,處理'新BarMessage'的輸出應該是'bar2bar1'(因爲ComponentType2在你的例子中有優先權)。是否可以實現pf作爲方法並讓它調用'super.pf'? – GKelly 2011-03-25 08:26:45

0

出於完整性:

trait Message 
class FooMessage extends Message 
class BarMessage extends Message 

trait Component { 
    def handleMessage(msg: Message) {} 
} 

trait ComponentType1 extends Component { 
    def handleMessage(msg: Message) { 
    msg match { 
     case m: FooMessage => println("foo1") 
     case m: BarMessage => println("bar1") 
     case _ => super.handleMessage(msg) 
    } 
    } 
} 

trait ComponentType2 extends Component { 
    override def handleMessage(msg: Message) { 
    msg match { 
     case m: BarMessage => 
     println("bar2") 
     super.handleMessage(m) // cascade 
     case _ => super.handleMessage(msg) 
    } 
    } 
} 

object component1and2 extends ComponentType1 with ComponentType2 

component1and2.handleMessage(new FooMessage) 
component1and2.handleMessage(new BarMessage) 

打印

foo 
bar2 
bar1 
相關問題