Scala继承使用容器类的最佳实践

时间:2014-09-29 03:21:54

标签: scala inheritance

我已经构建了一些像这样的代码:

“HandlerArguments”类,它将接收所有处理程序子类所需的一堆工厂和其他帮助程序:

class HandlerArguments(
    val a: A,
    val b: B,
    val c: C) { 
    /* nothing here */
}

将使用HandlerArguments的Handler超类:

class Handler(val args: HandlerArguments) {
    def subHandler1 = new SubHandler1(args)
    def subHandler2 = new SubHandler2(args)
    def subHandler3 = new SubHandler3(args)
    var message: Message = null

    /* code here that invokes subHandler1, 2, or 3 based on a matcher */
    def invokeCommand(msg: Message) = {
        message = msg
        someCommand match {
                    case command1 => subHandler1.something()
            case command2 => subHandler2.something()
            case command3 => subHandler3.something()
        }
    }
}

subHandlers或subClasses:

class subHandler1(args: HandlerArguments) extends Handler(args) { 
...
    args.something.somethingElse(message.x)
...
}
class subHandler2(args: HandlerArguments) extends Handler(args) { ... }
class subHandler3(args: HandlerArguments) extends Handler(args) { ... }

在另一个文件中,我正在初始化Handler:

/* initializing Handler */
val args = new HandlerArguments(a, b, c)
val handler = new Handler(args)
handler.invokeCommand(someMsg)

我的问题是,

  1. 这是最好的方法吗?我想要实现的主要内容是不必在超类Handler和子类之间传递“消息”(即subHandler1.something(message))。

  2. 我如何使用HandlerArguments?我想过使用traits或抽象类,但这需要设置一次然后由Handler类使用。

  3. 我将args从Handler传递给SubHandlers似乎很奇怪,只是在extends子句中将它传递给Handler。有更好的方法吗?

  4. 思考?谢谢!

1 个答案:

答案 0 :(得分:1)

这里有一个命令/查找表模式的例子。

我能提供的一些事情是:

HandlerArguments设为case class。这样,它就会变得更加冗长,并且您可以获得许多额外的好处。

case class HandlerArguments(a: A, b: B, c: C)

你完成了。 case类构造函数的参数自动被视为vals

我可以看到的另一个问题是,从超类构造子类实例会导致堆栈溢出(因为子类构造也构造了一个超类实例,并且循环无限期地继续)。

但是,根据您的用例,您的HandlerSubHandler*类之间可能不应存在超类 - 子类关系。 subHandler*类是实际的处理程序,也就是说,它们是处理消息的类。您的Handler班只是向他们发送消息。你在这里可以做的事情如下:

case class HandlerArgs(a: A, b: B, c: C)

trait MessageHandler {
  val args: HandlerArgs 
  def handle(msg: String)
}

class Handler1(val args: HandlerArgs) extends MessageHandler {
  override def handle(msg: String) = ???
}

class Handler2(val args: HandlerArgs) extends MessageHandler {
  override def handle(msg: String) = ???
}

class Handler3(val args: HandlerArgs) extends MessageHandler {
  override def handle(msg: String) = ???
}

class MessageDispatcher(args: HandlerArgs) {
  private val messageHandler1 = new Handler1(args)
  private val messageHandler2 = new Handler2(args)
  private val messageHandler3 = new Handler3(args)

  def dispatch(message: String) {
    val someCommand: Command = ???
    someCommand match {
      case Command("command1") => messageHandler1.handle(message)
      case Command("command2") => messageHandler2.handle(message)
      case Command("command3") => messageHandler3.handle(message)
    }
  }
}

val dispatcher = new MessageDispatcher(HandlerArgs(new A, new B, new C))
dispatcher.dispatch("<some command>")

评论后更新

如果您希望所有实例共享消息,可以选择将模板模式添加到现有代码中:

trait MessageHandler {
  val args: HandlerArgs 
  private var message: Option[String] = None
  // Save the message in a common implementation, and...
  private def saveMessage(msg: String) {
    message = Option(msg)
  }

  def handle(msg: String) {
    saveMessage(msg)
    doSomethingWithMessage(msg)
  }

  // let the subclasses handle the the actual message handling
  protected def doSomethingWithMessage(msg: String)

}

class Handler1(val args: HandlerArgs) extends MessageHandler {
  override def doSomethingWithMessage(msg: String) = ???
}

// rest of the message handlers

当然,有几种方法可以做到这一点。

另一种方式,如评论中所讨论的,是使用单个元素容器。对于前。

class MessageHolder {
  var message: Option[String] = None
}

trait MessageHandler {
  val args: HandlerArgs
  val messageHolder: MessageHolder
  def handle(msg: String)
}

class Handler1(val args: HandlerArgs, 
               val messageHolder: MessageHolder) extends MessageHandler {
  override def handle(msg: String) = ???
}


class MessageDispatcher(args: HandlerArgs) {
  private val mh = new MessageHolder
  private val messageHandler1 = new Handler1(args, mh)
  private val messageHandler2 = new Handler2(args, mh)
  private val messageHandler3 = new Handler3(args, mh)

  def dispatch(message: String) {
    val someCommand: Command = ???
    mh.message = Option(message)
    // ...
  }
}