2015-06-18 53 views
0

這是akka actor的接收內部的模式匹配問題。特徵中某個對象內部的類型是什麼

我有這樣的代碼:

class ActorReservation(reservation: Reservation) extends Actor { 
    import Entry._ 
    import Customer._ 

    def receive: Actor.Receive = messages 

    def messages: Receive = { 
    case Entry.Get.Result(obj) => // process entry 

    case Customer.Get.Result(obj) => // process customer 
    } 

    def test: Receive = { 
    case e => 
     println(s"ClassName -> ${e.getClass.getName}") 
     println(s"isInstanceOf[GenericMessages#Get] -> ${isInstanceOf[GenericMessages[AppAny]#Get]}") 
    } 
} 

object Entry extends GenericMessages[EntryEntity] 
object Customer extends GenericMessages[CustomerEntity] 

trait GenericMessages[A <: AppAny] { 
    case class Get(id: Int) 
    object Get { case class Result(obj: Option[A]) } 
} //trait 

trait AppAny 
case class EntryEntity(id: Int) extends AppAny 
case class CustomerEntity(id: Int) extends AppAny 

我的演員能得到兩個信息:當它接收到的第一個一切順利找到,但當第二個到達它拋出和異常Customer可以投Entry.Get.ResultCustomer.Get.Result,到Entry,這是因爲第二條消息被第一條case所捕獲。

然後我改變與

def receive: Actor.Receive = test 

兩個消息顯示相同的類名GenericMessages$Get$Result接收,所以這就是爲什麼這兩個消息落在第一case

我試圖創建與GenericMessages#Get兩個消息的通用case但是這使得引用的類GetGenericMessages而不是對象Get

所以,我的問題是:有沒有辦法引用GenericMessages特性的Get對象中的Result類?有沒有另外一種方法可以使case避免這種模式匹配問題?


附加信息: 真正的男主角是一個普通演員的實現,因爲我需要在其他演員一樣的行爲。

消息Entry.Get.Result,Customer.Get.Result是由同一個演員(anotherActor ! Customer.Get)發送的先前消息的響應,並且以這種方式實現,因爲我傾向於並行調用而不是線性調用。線性解決方案是使用一種方法接收第一條消息,而不是使用become更改爲另一個接收並處理第二條消息。我想避免這種線性方法,因爲1.我更喜歡它是一個並行進程,2.它打破了我所做的抽象。

+0

是不是像說「你怎麼我區分龍在兩個不同的類?」他們本質上是一樣的,不是嗎?需要有一些外部方法(不在Long實例內)來確定Long實例屬於哪個類。 – bjfletcher

回答

0

我找到了解決方案。

,我決定加入第三object除了EntryCustomer

private object Messages extends GenericMessages[AppAny] 

,並更改接收功能與此

def messages: Receive = { 
    case Messages.Get.Result(obj) => 
    obj match { 
     case Some(e: Entry) =>  // process entry 
     case Some(c: Customer) => // process customer 
    } 
} 

現在的作品,因爲它需要。


的完整代碼:

class ActorReservation(reservation: Reservation) extends Actor { 
    import Entry._ 
    import Customer._ 

    def receive: Actor.Receive = messages 

    def messages: Receive = { 
    case Messages.Get.Result(obj) => 
     obj match { 
     case Some(e: Entry) =>  // process entry 
     case Some(c: Customer) => // process customer 
     } 
    } 
} 

private object Messages extends GenericMessages[AppAny] 
//I still need this two objects because they are part of 
//other service that use this messages 
object Entry extends GenericMessages[EntryEntity] 
object Customer extends GenericMessages[CustomerEntity] 

trait GenericMessages[A <: AppAny] { 
    case class Get(id: Int) 
    object Get { case class Result(obj: Option[A]) } 
} //trait 

trait AppAny 
case class EntryEntity(id: Int) extends AppAny 
case class CustomerEntity(id: Int) extends AppAny 
0

有一個解決方案(這是非常醜陋的):請輸入和客戶分成類:

case class Entry() extends GenericMessages[EntryEntity] 
case class Customer() extends GenericMessages[CustomerEntity] 

然後創建一個條目和客戶實例:

val entry = Entry() 
val customer = Customer() 

,並將其作爲參數傳遞給你的ActorReservation actor(以及任何需要它的人)。然後創建並匹配,如下所示:

entry.Get.Result 
customer.Get.Result 

但這是糟糕的設計。

我建議在與演員合作時避免使用泛型。當您需要在運行時匹配類型時,類型擦除成爲一個問題。 如果我是你,我會重做設計。