簡體   English   中英

在Scala中繼承自我類型特征與另一個特征

[英]Inheriting self-typed trait with another trait in Scala

我正在嘗試為我的應用程序設計一個小模塊系統,以便我可以這樣做:

new MyApplication extends Module1 with Module2 ... with ModuleN

為了讓我的模塊在應用程序中注冊自己,我還有:

trait ModuleRegistry {
  def register(start: () => Unit) = // Stores start functions in a list
}

trait Module {
  self: ModuleRegistry =>
  self.register(start)
  def start(): Unit
}

class Application extends ModuleRegistry {
}

trait Module1 extends Module {
  ...
}

我們的想法是,模塊可以在應用程序啟動時注冊要調用的注冊表函數。 不幸的是,Scala編譯器迫使我這樣做:

trait Module1 extends Module {
  self: ModuleRegistry =>
}

這意味着模塊的所有實現都必須使用注冊表顯式地自我鍵入,理想情況下,他們不知道它。

所以我的問題是:

  1. 為什么編譯器強迫我在擴展特征上重新指定這個自我類型? 理想情況下,我甚至不希望擴展特征“看到”這種類型,因為它應該由基本模塊特征處理。 “具體”模塊旨在由第三方實施,因此將注冊表暴露給它們似乎有點難看。
  2. 有沒有更好的方法來做我想在Scala中實現的功能,以便模塊可以自由混合?

這不是對蛋糕模式的好用,因為你希望所有模塊都保留它們自己的功能(大概),混合時不要混合和覆蓋。如果你想要后者,你不應該:只有非常謹慎的設計可以提供可預測和合理的結果,如果第三方應該提供模塊,那么設計就不會那么小心了。

相反,你應該堅持“贊成組合而不是繼承”的建議。

trait Module {
  def start: Unit
}

trait Modular {
  protected def moduleList: Seq[Module]
  protected def register() = moduleList.map(m => m.start _)
}

class Application(modules: Module*) extends Modular {
  protected def moduleList: Seq[Module] = modules  // Fix varargs type
  protected val registered = register()
}

object Module1 extends Module {
  def start = println("One")
}

object Module2 extends Module {
  def start = println("Two")
}

val app = new Application(Module1, Module2) {
 registered.foreach(_())
}
// Prints "One", then "Two"

這假設單個模塊可以正常使用。 如果您需要特定實例,則可以在配對對象中覆蓋apply(語法為Module1()),或者添加Module1擴展的構建器特征(例如trait ModuleBuilder { def module: Module } )。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM