简体   繁体   English

避免与Cake Pattern名称冲突

[英]Avoid name collision with Cake Pattern

I'm currently currently using the Cake Pattern to implement some optimization algorithms. 我目前正在使用Cake Pattern来实现一些优化算法。 I often hit name collision problems. 我经常遇到名字碰撞问题。 For instance: 例如:

trait Add[T] { this: Foo[T] =>
  def constant: T
  def plus( t1: T, t2: T ): T
  def add( t: T ) = plus( t, constant )
}

trait Mul[T] { this: Bar[T] =>
  def constant: T
  def times( t1: T, t2: T ): T
  def mul( t: T ) = times( t, constant )
}

trait Operations[T] { this: Add[T] with Mul[T] =>
  def neg( t: T ): T
}

Here, constant is defined in both Add and Mul traits, but their values could be different. 这里, constantAddMul特征中定义,但它们的值可能不同。 I could prefix the name with the trait name but I find it ugly and brittle ( def mulConstant: T ). 我可以在名称前加上特征名称,但我觉得它很丑陋( def mulConstant: T )。 Is there a better way of doing it ? 有没有更好的方法呢?

To my best knowledge, the traditional cake pattern usually involves 1 layer of trait nesting, to group operations together. 据我所知,传统的蛋糕模式通常涉及1层特性嵌套,以便将操作组合在一起。 Then, the outer layer declares the actual "service" (here: Add, Mul, Operations) without defining it. 然后,外层声明实际的“服务”(这里:添加,Mul,操作)而不定义它。

trait AddComponent[T] { this: FooComponent[T] =>
  def addition: Add

  trait Add {
    def constant: T
    def plus( t1: T, t2: T ): T
    def add( t: T ) = plus( t, constant )
  }
}

trait MulComponent[T] { this: BarComponent[T] =>
  def multiplication: Mul

  trait Mul {
    def constant: T
    def times( t1: T, t2: T ): T
    def mul( t: T ) = times( t, constant )
  }
}

trait OperationsComponent[T] { this: Add[T] with Mul[T] =>
  def operations: Operations

  trait Operations {
    def neg( t: T ): T
  }
}

Then, when mixing the "...Component" traits together, the dependencies are wired: 然后,当将“... Component”特征混合在一起时,依赖关系是有线的:

trait IntOperations extends Operation[Int] {
  class IntAdd extends Add { ... }
  class IntMul extends Mul { ... }
}

class MyFooBar extends FooComponent[Int] with BarComponent[Int] with IntOperations {
  lazy val addition = new IntAdd
  lazy val multiplication = new IntMul
  lazy val foo = ...
  lazy val bar = ...
}

This solves your particular namespacing problem but name clashes (of "service" definitions) remain a problem of the traditional cake pattern. 这解决了您的特定命名空间问题,但名称冲突(“服务”定义)仍然是传统蛋糕模式的问题。 There is a blog post by Daniel Spiewak demonstrating how that can be solved in general but the solution comes with its own set of (huge) tradeoffs (see this talk ). Daniel Spiewak 发表一篇博客文章 ,演示了如何解决这个问题,但解决方案有自己的一套(巨大的)权衡(参见本演讲 )。

Hope that helped a bit. 希望有所帮助。

PS instead of type parameters it might be better to use abstract types here PS而不是类型参数在这里使用抽象类型可能更好

This may be a bit unfashionable to say, and it's not a direct answer to your question, but isn't it easier to simply do dependency injection into constructors? 这可能有点不合时宜,而且它不是你问题的直接答案,但是简单地将依赖注入到构造函数中并不容易吗? Each collaborator has its own namespace so there's never a clash. 每个协作者都有自己的命名空间,因此永远不会发生冲突。 And there's no problem either with the public api of the class. 并且对于班级的公共api也没有问题。 However, it remains hard to intermix the DI and cake patterns. 然而,仍然难以混合DI和蛋糕模式。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM