2014-09-29 74 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