我有一个非常通用的消息对象,我从队列中回来:
case class Message(key: String, properties: Map[String, String])
然后我有一堆非常具体的类来表示消息,我使用properties.get(“type”)来确定它是哪个特定的消息:
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 ...
}
我有什么选择可以减少scala中的麻烦?
答案 0 :(得分: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.
}
}
}
就是这样!它可能不是最佳解决方案,因为暗示会带来复杂性,并且使代码更难以遵循。但是,如果您遵循一个定义良好的结构来存储这些隐式值,并且要小心如何传递它们,那么您不应该有任何问题。
答案 1 :(得分: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
}
}
}
签名可能会有所不同,具体取决于您希望如何处理错误处理。