2014-09-29 70 views
1

我已经架构了一些这样的代码:Scala的继承最佳实践

A“HandlerArguments”类,将采取在一堆工厂,需要对所有的处理程序子类其他佣工:

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

一个处理器的超类将在HandlerArguments:

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,或子类:

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

而在另一个文件中,我初始化处理程序:

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

我的问题是,

  1. 这是做到这一点的最好方法是什么?我想实现的主要目的不是在超类Handler和子类之间传递'message'(即subHandler1.something(message))。

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

  3. 看起来很奇怪,我把从处理程序到子处理程序的参数传递给扩展子句中的处理程序。有一个更好的方法吗?

想法?谢谢!

回答

1

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

几件事情,我可以提供我的头的顶部是:

使HandlerArguments一个case class。这样,它就不那么冗长了,而且还有很多额外的好处。

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

你就完成了。案例类构造函数的参数被自动考虑为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) 
    // ... 
    } 
} 
+0

谢谢你非常透彻的答案!然而,其中一个要点是我想要传递给messageHandlers的消息和messageHandlers本身之间的关系更紧密。实际上,这个消息实际上是一个类的实例,我宁愿只住在一个地方,所有的messageHandlers都可以访问,因此上面的超类/子类实现。这个新的实现可能吗? – jnfr 2014-09-29 04:47:40

+0

当然,这是可能的。在MessageDispatcher初始化的所有MessageHandlers之间可以有某种共享容器。该容器可以作为构造函数参数传递给MessageHandlers(可以是'Option [Command]'或'MessageBox(Command)')。如果需要的话,这甚至会允许线程安全。当然有多种方式可以做到这一点。我可以举一个例子。 – 2014-09-29 04:56:50

+0

如果它作为构造函数参数传递给每个MessageHandlers,那么这不是消息与处理程序的1:1映射吗?除非我误解实现...一个例子将不胜感激:)谢谢! – jnfr 2014-09-29 05:08:48