“几乎是”斯卡拉的关系

时间:2011-11-11 06:54:55

标签: scala mixins

我正在尝试设计一个类层次结构,其中包含许多类似的类,这些类并不完全共享“是一种”关系。我们称这些Model类。这些类旨在与类似算法的集合配对,这些算法使用Model类但不具有相同的要求。我们称这些Strategy类。诀窍是Strategy类需要来自Model类的许多相同的东西,但并非所有Model类都能够实现那些所需的方法。我希望没有空的“存根”方法只会抛出UnsupportedOperationException,而是采用类型安全的基于mixin的方式来处理这个问题 - 我是否可以应用一种设计模式? / p>

例如,

object Main extends App {
    trait A {
        def f(one: Int): Int
        def g(two: Int): Int
        def h(three: Int): Int
    }

    class A1 extends A {
        override def f(one: Int): Int = {one + 1}
        override def g(two: Int): Int = {two + 2}
        override def h(three: Int): Int = {assert(false); 0}
    }

    class A2 extends A {
        override def f(one: Int): Int = {assert(false); 0}
        override def g(two: Int): Int = {two - 2}
        override def h(three: Int): Int = {three - 3}
    }

    trait B {
        def combine(i: Int): Int
    }

    trait B1 extends B {
        this: A =>
        override def combine(i: Int) = {f(i) + g(i)}
    }

    trait B2 extends B {
        this: A =>
        override def combine(i: Int) = {g(i) + h(i)}
    }

    override def main(args: Array[String]): Unit = {
        val a11 = new A1 with B1
        val a22 = new A2 with B2

        println(a11.combine(3))
        println(a22.combine(3))

        val a12 = new A1 with B2
        println(a12.combine(3))
    }
}

此处AModel类,BStrategy类。请注意,A1可能无法实施h(),而A2可能无法实施f(),并且根据策略类别,这可能是也可能不是问题。我希望能够找到A的哪个实现可以在编译时使用哪个B实现。

我已经使用self-types来表达更多“有一个”而不是“一个”的关系,通常会延伸。

2 个答案:

答案 0 :(得分:5)

这是我的解决方案:

trait F { def f(one: Int): Int }
trait G { def g(two: Int): Int }
trait H { def h(three: Int): Int }

trait A
trait A1 extends A with F with G {
  def f(one: Int): Int = { one + 1 }
  def g(two: Int): Int = { two + 2 }
}
trait A2 extends A with G with H {
  def g(two: Int): Int = { two - 2 }
  def h(three: Int): Int = { three - 3 }
}

trait B {
  def combine(i: Int): Int
}
trait B1 extends B {
  this: A with F with G =>
  def combine(i: Int) = { f(i) + g(i) }
}
trait B2 extends B {
  this: A with G with H =>
  def combine(i: Int) = { g(i) + h(i) }
}

val a11 = new A1 with B1
val a22 = new A2 with B2

println(a11.combine(3))
println(a22.combine(3))

val a12 = new A1 with B2 // won't compile as you wanted

答案 1 :(得分:2)

您也可以使用结构类型,这些类甚至不需要在其层次结构中相关:

class A1 {
  def f(i: Int) = {i + 1}
  def g(i: Int) = {i + 2}
}

class A2 {
  def g(i: Int) = {i * 2}
  def h(i: Int) = {i * i}
}

type FnG = { def f(i: Int): Int; def g(i: Int): Int}

class B {
  def combine1(a: FnG, i: Int) = a.f(i) + a.g(i)
  def combine2(a: { def g(i: Int): Int; def h(i: Int): Int}, i: Int) = 
      a.g(i) + a.h(i)
}

val a1 = new A1
val a2 = new A2
val b = new B
println(b combine1(a1, 3))
println(b combine2(a2, 3))

trait C {
  def combine(i: Int): Int
}
trait C1 extends C {
  this: FnG =>
  def combine(i: Int) = f(i) + g(i)
}
trait C2 extends C {
  this: { def g(i: Int): Int; def h(i: Int): Int} =>
  def combine(i: Int) = g(i) + h(i)
}

val newA1 = new A1 with C1
val newA2 = new A2 with C2

println(newA1 combine(3))
println(newA2 combine(3))

这样,您只需要指定(对于traits)基类型支持特定方法,对于类,指定传入的类支持特定方法。您不需要假设任何层次结构。