我正在尝试设计一个类层次结构,其中包含许多类似的类,这些类并不完全共享“是一种”关系。我们称这些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))
}
}
此处A
是Model
类,B
是Strategy
类。请注意,A1
可能无法实施h()
,而A2
可能无法实施f()
,并且根据策略类别,这可能是也可能不是问题。我希望能够找到A的哪个实现可以在编译时使用哪个B实现。
我已经使用self-types来表达更多“有一个”而不是“一个”的关系,通常会延伸。
答案 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)基类型支持特定方法,对于类,指定传入的类支持特定方法。您不需要假设任何层次结构。