繁体   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