2017-02-28 19 views
0

を変換し、それはある特定のどのメッセージを決定するためにproperties.get(「タイプ」)を使用します。は私がように戻って、キューから取得する非常に一般的なメッセージオブジェクトを持つクラス

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

は今、私のコードで私は多くの場所で特定のメッセージに、一般的なメッセージから変換する必要があり、私はこれを作成したいです次のような単一の場所で:

私はScalaではこれはあまり面倒な作りにしていますどのようなオプション

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

今の実装の両方を保持し、またMessageインスタンス上の素敵な#as[T]メソッド可能オブジェクト定義:

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

それだけです!暗黙的に複雑さが増し、コードの実行が困難になるため、最適な解決策ではないかもしれません。しかし、これらの暗黙的な値を格納するための明確な構造に従って、それらを渡す方法に注意するならば、何の問題もないはずです。

関連する問題