簡體   English   中英

延遲特質初始化

[英]Delaying trait initialization

我需要一個智能的組件組合機制,它允許混合特性在組合組件之后初始化。 以下拋出NullPointerException

class Component {
  def addListener(pf: PartialFunction[Any, Unit]) {}
}

trait DynamicComponent {
  protected def component: Component

  component.addListener {
    case x =>
  }
}

class Foo extends DynamicComponent {
  protected val component = new Component
}

new Foo  // -> NullPointerException

以下內容對我來說不是選項

  • 使用protected lazy val component ; 這會產生幾十個需要變得懶惰的val ,這是我不想要的
  • addListener放在方法中,例如initDynamic() ; 因為我將混合許多特征,我不想記得調用半打initFoo()方法。
  • 使用DelayedInit 這不適用於特征,至少根據scaladocs。

我可以使用單個init()調用,但僅限於以下條件:

  • 在這一個單一的調用中,所有混合的特征都可以很容易地聲明被調用
  • 忘記init()語句是一個編譯錯誤。

您可以通過使用早期定義來延遲特征的初始化。 (參見scala語言規范的 5.1.6節)

class Foo extends {
  protected val component = new Component
} with DynamicComponent

它甚至比你的解決方案更笨拙,但是你總是需要創建一個必須用init()方法設置的val。 可以選擇不做最后一次並在運行時出錯,但至少你不會完全忘記它:

class Component {
  def addListener(pf: PartialFunction[Any, Unit]) {
    println("Added")
  }
}

trait Dyn {
  protected def component: Component
  protected val initialized: Init
  class Init private () {}
  private object Init { def apply() = new Init() }
  def init() = { component.addListener{ case x => }; Init() }
}

class Foo extends Dyn {
  protected val component = new Component
  protected val initialized = init()
}

別作弊!:

> class Bar extends Dyn { protected val component = new Component }
<console>:12: error: class Bar needs to be abstract, since value
initialized in trait Dyn of type Bar.this.Init is not defined
       class Bar extends Dyn { protected val component = new Component }

這樣做的好處是,如果你在合作初始化所有這些東西之前需要多個東西,或者你的Component類是final那么你就不能混入任何其他東西。

一個想法可能是使用這里描述的技巧: 蛋糕模式:如何獲取組件提供的UserService類型的所有對象

應該初始化的所有組件都可以在一些Seq[InitializableComponent]注冊。 然后,您可以使用foreach初始化所有已注冊的組件。

在Seq中不會忘記任何組件,因為它們是自動注冊的,但是你仍然可以忘記給foreach打電話......

這是一個想法(我很高興看到其他建議):

class Component {
  def addListener(pf: PartialFunction[Any, Unit]) {
    println("Added")
  }
}  

trait DynamicComponentHost {
  protected def component: Component with DynamicPeer

  protected trait DynamicPeer {
    _: Component =>
    addListener {
      case x =>
    }
  }
}

class Foo extends DynamicComponentHost {
  protected val component = new Component with DynamicPeer
}

new Foo

所以基本上我強迫組件混合在一個只能由混合特性提供的類型中。 合理? 在我眼里看起來有點太復雜了。

暫無
暫無

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

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