Delaying trait initialization

做~自己de王妃 提交于 2019-12-05 09:16:20

You can delay the initialization of a trait by by using early definitions. (See section 5.1.6 of the scala language specification)

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

It's even clunkier than your solution, but you can always require the creation of a val that must be set with the init() method. You could choose to not do it last and get an error at runtime, but at least you won't forget it entirely:

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()
}

No cheating!:

> 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 }

The advantage this has is if you need multiple things to be in place before you initialize all of them cooperatively, or if your Component class is final so you can't mix in anything else.

Sebastien Lorber

AN idea could be to use the trick described here: Cake pattern: how to get all objects of type UserService provided by components

All your components that should be initialized could be registered in some Seq[InitializableComponent]. And then you could initialize all registered components with a foreach.

No component will be forgotten in that Seq because they are registered automatically, but you can still forget to call the foreach anyway...

Here is one idea (I am happy to read about other suggestions):

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

So basically I am forcing the component to mix in a type that can only be provided by the mixed in trait. Reasonable? Looks a bit too complicated in my eyes.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!