【问题标题】:Scala design help, pattern matching on abstract class or traitScala 设计帮助,抽象类或特征的模式匹配
【发布时间】:2013-05-28 12:30:53
【问题描述】:

编辑:我重写了我的问题以澄清并包括我想要实现的目标。

我正在构建一个使用 Akka 发送消息的系统。我正在使用一些小型服务来构建它。我有一个共享核心库,我的所有消息都作为案例类驻留在其中。这些构成了我的服务之间的合同。

我希望能够做到以下几点,但是在抽象类消息的模式匹配中出现编译错误:

case class Source( serviceId: String, time: String )
case class Credentials( tenantId:String, userId: String )
sealed abstract class Message( credentials:Credentials, sources: Vector[Source] )
trait FormEvent
trait MailEvent

case class FetchQuestion( questionId: String, credentials:Credentials, sources: Vector[Source] ) extends Message( credentials, sources ) with FormEvent
case class MailQuestion( questionId: String, credentials: Credentials, sources: Vector[Sources]) extends Message( credentials, sources ) with MailEvent

def route( msg:Message, tenantId: String, sources: Vector[Source] ) = msg match {
  case fe:FormEvent => s"form message for $tenantId with sources $sources."
  case me:MailEvent => s"mail message for $tenantId with sources $sources."
}

// Emulated Akka Receive, compilation error when matching.
def receive( a: Any ) = a match {
  case msg@Message( credentials, srs ) => route( msg.copy( sources = (srs :+ Source( "routing", "justnow" ) ) ), credentials.tenantId, srs) 
}

所以模式匹配的契约似乎与案例类紧密耦合,我需要采取哪些步骤来创建一个行为类似于案例类的超类?


这是提取器的相同示例。

case class Source( serviceId: String, time: String )
case class Credentials( tenantId:String, userId: String )
case class Trail(credentials: Credentials, sources: Vector[Source] )
trait Message {
  def trail: Trail
}

object Message {
  def unapply( msg: Message ) = Option( msg.trail ) 
}

trait FormEvent
trait MailEvent

case class FetchQuestion( questionId: String, trail:Trail ) extends Message with FormEvent
case class MailQuestion( questionId: String, trail:Trail ) extends Message with MailEvent

def route( msg:Message, tenantId: String, newSources: Vector[Source] ) = msg match {
  case fe:FormEvent => s"form message $msg for $tenantId with sources $newSources."
  case me:MailEvent => s"mail message $msg for $tenantId with sources $newSources."
}

// Emulated Akka Receive, compilation error when matching.
def receive( a: Any ) = a match {
  case msg@Message( Trail( Credentials( tenantId, _ ), srs ) ) => route( msg, tenantId, (srs :+ Source( "routing", "justnow" ) ) ) 
}

val fq = FetchQuestion( "question1", Trail( Credentials( "tenant", "user"), Vector( Source( "service1", "before" ) ) ) )

receive( fq )

【问题讨论】:

标签: scala inheritance pattern-matching traits


【解决方案1】:

您要查找的是extractors (unapply, unapplySeq)

但我建议您简化您的设计,而不是实施它。你的多层次继承方法太混乱了,我认为没有任何实际需要。


摆脱抽象类至少使您的继承模式统一。但是,您的设计问题仍然存在,并且您过早地进行了优化。

首先,在正确的方法中,您必须发现自己在这些特定情况下的模式匹配过多,然后才应该为它寻找解决方案,反之亦然。不要试图解决你还没有面对的问题,而是专注于你的实际问题。在大多数情况下,稍后您会发现并没有真正需要这些优化,或者到那时您的应用程序会发生很大变化,以至于整个优化问题都会过时。所以从简单开始,只有在必要时才变得更复杂。

【讨论】:

  • 不确定多层次继承的具体含义是什么?您是指使用多个特征吗?我修改后的提取器示例仅使用特征,之前我不是自己选择拥有抽象类的。我有这些特征来确保我的应用程序的不同部分可以处理一般情况,而不是在模式匹配时处理最具体的情况。
  • 我最初的帖子(为了便于阅读而缩短了)实际上表示我认为解决方案对于抽象类或带有泛型的特征变得过于复杂。所以,是的,你说得有道理。但这些都不是过早的优化。我将服务拆分为不同 JVM:s 上的小应用程序。我需要一种统一的方法来处理横切关注点,并通过 FormEvent、MailEvent 等特征轻松路由以更正服务,而不是在多个级别上匹配 20-30 种消息类型。
  • 要明确一点:我不认为你总体上是错的,只是我不明白当你没有看到整个应用程序和以前的版本。
猜你喜欢
  • 2015-10-02
  • 2016-10-13
  • 1970-01-01
  • 2016-09-04
  • 2020-11-28
  • 1970-01-01
  • 2012-07-10
  • 2011-11-19
  • 1970-01-01
相关资源
最近更新 更多