6

让我们假设我们有一个 trait T。实现以下目标的最佳方法是什么:

  • 每个编写 的实现的人都T应该被迫提供一种允许 的无参数初始化的可能性T,即,我们可能必须强制执行可配置工厂的实现。
  • 所有仅依赖于(的某个实现AT)实际初始化参数的逻辑/数据都应该集中处理/存储,但应该在工厂和A.

我看到实现这一点的最简单/简洁的方法(大约)是为工厂添加一个特征并链接T到该工厂:

trait T {
  val factory: TFactory
}
trait TFactory {
  def build(): T
  val description: String   // example for logic/data that only depend on the parameters
}

// example implementation:
class A(val factory: AFactory, paramA: Int, paramB: Int, paramC: Int) extends T

class AFactory(paramA: Int, paramB: Int, paramC: Int) extends TFactory {
  def build = new A(this, paramA, paramB, paramC)
  val description = f"$paramA $paramB $paramC"
}

显然,这并没有真正“强制”工厂的实现(只要有可用的替代实现),并且显然可以生成A指向“错误”的链接的实例化TFactory。我也不喜欢这种方法的是初始化参数的重复。我经常创建另一个类AParams,它再次包装所有参数(例如为了方便添加新参数)。因此,我最终得到了三个类,恕我直言,这是这个简单问题的很多样板。

我的问题是是否有(可能完全)不同的方法,它实现了相同的主要目标但更简洁?

4

2 回答 2

1

我不太确定我是否完全了解您的要求,但您如何看待这种行为?

trait TFactory{
    def build():T
    val description:String
}

trait T extends TFactory

//can't declare A without build and not make it abstract
class A(paramA: Int, paramB: Int, paramC: Int) extends T {
    def build = new A(paramA, paramB, paramC)
    val description = f"$paramA $paramB $paramC"    
}

val a1 = new A(1, 4, 5)
val a2 = a1.build()

//We can give ourselves as a factory to something that expects TFactory
val factory:TFactory = a1
val a_new = factory.build()

//More likely we can just give our build method
def func(f: ()=>T) = {
    val new_t = f()
    new_t
}
val a_newer = func(a1.build)


println(a1 +": " + a1.description)
println(a2 +": " + a2.description)
println(a_new +": " + a_new.description)
println(a_newer +": " + a_newer.description)

输出:

Main$$anon$1$A@69267649: 1 4 5
Main$$anon$1$A@69b1fbf4: 1 4 5
Main$$anon$1$A@24148662: 1 4 5
Main$$anon$1$A@3f829e6f: 1 4 5
于 2013-12-12T14:44:45.317 回答
1

添加表示类型参数:

trait Factory[Prod] {
  def build(): Prod
}

trait Prod[Repr] {
  def factory: Factory[Repr]
}

或者,如果您想“强制”类型保持不变(除非您从中获得一些东西,否则我不会这样做):

trait Prod[Repr <: Prod[Repr]] {
  def factory: Factory[Repr]
}

然后:

case class AConfig(a: Int, b: Int)

case class A(config: AConfig) extends Prod[A] {
  def factory = AFactory(config)
}

case class AFactory(config: AConfig) extends Factory[A] {
  def build() = A(config)
}

val f0 = AFactory(AConfig(1, 2))
val p0 = f0.build()
val f1 = p0.factory
val p1 = f1.build()
assert(p0 == p1)
于 2013-12-13T10:03:18.430 回答