2017-02-28 88 views
0

我有一個非常普通的消息對象,我得到一個隊列就像回到:如何創建自己的自定義轉換

case class Message(key: String, properties: Map[String, String]) 

然後我有一堆代表的消息非常具體的類,我使用properties.get(「類型」),以確定它是特定消息:

sealed trait BaseMessage 
case class LoginMessage(userId: Int, ....) extends BaseMessage 
case class RegisterMessage(email: String, firstName: String, ....) extends BaseMessage 

現在在我的代碼,我不得不從通用消息轉換爲在許多地方一個特定的消息,我想創建此在一個地方如:

目前,我做這樣的事情:

val m = Message(....) 
val myMessage = m.properties.get("type") match { 
    case Some("login") => LoginMessage(m.properties("userID"), ...) 
    case ... 
} 

我必須在作出這一階不太麻煩什麼選擇?

+0

不使用'Map [String,String]'來存儲初學者的任意屬性。恢復這些信息並不容易。 –

+0

無形可能可以幫助,如果你想保持類型安全 – LMeyer

+0

@MichaelZajac該類是從消息隊列系統,不能改變。 – Blankman

回答

0

您可以將properties地圖轉換爲Json並將其作爲案例類讀取。假設鍵映射具有相同的名稱爲您的案件類字段,你可以使用playjson寫格式化:

object LoginMessage { 
    implicit val fmtLoginMessage = Json.format[LoginMessage] 
} 

如果字段不具有相同的名稱,你將不得不手動指定的讀取對象。您的代碼將其轉換成一個案例類會是這樣的:

object BaseMessageFactory { 
    def getMessage(msg: Message): Option[BaseMessage] = { 
    val propertiesJson = Json.toJson(msg.properties) 
    msg.properties.get("type").map { 
     case "login" => propertiesJson.as[LoginMessage] 
      ... 
     case _ => //Some error 
    } 
    } 
} 

簽名可能取決於您希望如何處理錯誤處理不同。

1

我不知道你在這裏的所有情況,但我可以建議使用隱式轉換,如果你不想在你的項目中帶來另一個庫。無論如何,隱式轉換可以幫助您分離很多實現,或根據需要「實時」覆蓋它。

我們可以通過定義一個MessageConverter特徵,實際上是一個函數開始:

/** 
    * Try[T] here is useful to track deserialization errors. If you don't need it you can use Option[T] instead. 
    */ 
trait MessageConverter[T <: BaseMessage] extends (Message => Try[T]) 

現在定義是同時擁有的實現目標,也實現了不錯的#as[T]方法上Message實例:

object MessageConverters { 
    /** 
    * Useful to perform conversions such as: 
    * {{{ 
    * import MessageConverters._ 
    * 
    * message.as[LoginMessage] 
    * message.as[RegisterMessage] 
    * }}} 
    */ 
    implicit class MessageConv(val message: Message) extends AnyVal { 
    def as[T <: BaseMessage : MessageConverter]: Try[T] = 
     implicitly[MessageConverter[T]].apply(message) 
    } 

    // Define below message converters for each particular type 

    implicit val loginMessageConverter = new MessageConverter[LoginMessage] { 
    override def apply(message: Message): Try[LoginMessage] = { 
     // Parse the properties and build the instance here or fail if you can't. 
    } 
    } 
} 

就是這樣!它可能不是最好的解決方案,因爲這會帶來複雜性,並使代碼難以遵循。但是,如果您遵循一個定義良好的結構來存儲這些隱式值,並小心如何傳遞它們,那麼您就不應該有任何問題。

相關問題