通过scala中的mixins管理依赖关系图

时间:2017-05-03 08:14:58

标签: scala dependency-injection mixins

我有一个类需要2个特征,这两个特征都需要相同的特性。我如何在这种情况下添加它

class RandomTest extends AbstractTestCase {
  "asdasd" should "asdsda" in {
    val a = new Application with XYZAppName with Session with MetricsPublisher

    a.a()
  }

  abstract class Application extends Session with MetricsPublisher {

    println("Application")
    def a() : Unit = { println("application.a")}
  }



  trait RequiredAppContext {
    println("RequiredAppContext")
    val appName : String
  }

  trait MetricsPublisher extends RequiredAppContext {
    this:RequiredAppContext =>
    println("MetricsPublisher")
  }
  trait Session extends RequiredAppContext{
    this:RequiredAppContext =>
    println("Session")
    lazy val appNameoverload = func(appName)
    def func(value:String ) {println("appNameoverload "+appName)}

  }


  // implmentations
  trait XYZAppName extends RequiredAppContext {
    println("XYZAppName")
    override val appName = "xyz"
  }
}

以下是该程序的输出:

 [scalatest] RequiredAppContext 
 [scalatest] Session 
 [scalatest] MetricsPublisher 
 [scalatest] Application 
 [scalatest] XYZAppName
 [scalatest] application.a

将XYZAppName初始化移至Session之前的最佳方法是什么?

1 个答案:

答案 0 :(得分:1)

Scala的线性化算法,管理特征图初始化顺序和解决钻石继承问题,以声明顺序遍历(非循环)继承图,满足初始化父节点的要求,但省略已经初始化的所有重复项。这里的问题是,要初始化某个类,首先需要初始化它的基类,以及扩展它的所有特性。 Scala甚至不允许在extendsnew之后的任何位置指定基类 - 您只能使用with添加特征。对于({1}}基类的(匿名)类是a

Application

因此,您唯一的选择是修改您的继承层次结构,将a.type -> Application -> Session -> RequiredAppContext -> MetricsPublisher -> RequiredAppContext // omitted -> XYZAppName -> RequiredAppContext // omitted -> Session // omitted -> RequiredAppContext // parent omitted -> MetricsPublisher // omitted -> RequiredAppContext // parent omitted 转换为特征,然后在Application的定义中使用XYZAppName对其进行重新排序:

a

然而,该解决方案无法涵盖所有​​可能的情况 - 如果您的抽象类具有构造函数,则无法将其转换为特征(有ongoing work在未来版本的Scala中允许特征参数,但是它还远未完成)。如果基类是在外部代码中定义的,那么它也不是一个选项。