&引用;几乎是一个;Scala中的关系
我正在尝试设计一个类层次结构,其中包含一组类似的类,它们并不完全共享“是a”关系。让我们把这些类称为&引用;几乎是一个;Scala中的关系,scala,mixins,Scala,Mixins,我正在尝试设计一个类层次结构,其中包含一组类似的类,它们并不完全共享“是a”关系。让我们把这些类称为Model类。这些类意味着与使用模型类但不具有相同要求的类似算法集合配对。让我们把这些称为策略类。诀窍在于策略类需要从模型类中获得许多相同的东西,但并非所有模型类都能够实现这些所需的方法。我不想让空的“存根”方法只抛出UnsupportedOperationExceptions,而是用一种基于类型安全的mixin方法来处理这个问题——我可以应用一种设计模式吗 比如说, object Main ex
Model
类。这些类意味着与使用模型
类但不具有相同要求的类似算法集合配对。让我们把这些称为策略类。诀窍在于策略
类需要从模型
类中获得许多相同的东西,但并非所有模型
类都能够实现这些所需的方法。我不想让空的“存根”方法只抛出UnsupportedOperationException
s,而是用一种基于类型安全的mixin方法来处理这个问题——我可以应用一种设计模式吗
比如说,
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
是模型
类,B
是策略
类。请注意,A1
可能无法实现h()
,A2
可能无法实现f()
,这取决于策略类,可能是问题,也可能不是问题。我希望能够找出A的哪个实现可以在编译时与B的哪个实现一起工作
我曾经表达过一种“hasathan”关系,这种关系通常会伴随扩展而来。这里是我的解决方案:
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
以下是我的解决方案:
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
您还可以使用结构类型,这些类甚至不需要在其层次结构中关联:
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)基类型支持特定方法,对于类,传入类支持特定方法。您不需要假定任何层次结构。您也可以使用结构类型,这些类甚至不需要在其层次结构中关联:
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)基类型支持特定方法,对于类,传入类支持特定方法。你不需要假设任何层次结构。注意你的覆盖
修饰符是不必要的。@PeterSchmitz我知道,但我发现它可以帮助我跟踪哪些方法正在实现某种接口。注意你的覆盖
修饰符是不必要的。@PeterSchmitz我知道,但是我发现它可以帮助我跟踪哪些方法正在实现某种接口。谢谢!我也想过,但这真的是最好的解决方案吗?我觉得它非常冗长。这是scala.collections
库中的主要工作方式吗?据我所知,在collections库中,事情并不是以模型
-策略
的方式组成的。有一个层次结构,CanBuildFrom
,以确保“最佳”返回类型。但也许其他人可以澄清这一点。谢谢!我也想过,但这真的是最好的解决方案吗?我觉得它非常冗长。这是scala.collections
库中的主要工作方式吗?据我所知,在collections库中,事情并不是以模型
-策略
的方式组成的。有一个层次结构,CanBuildFrom
,以确保“最佳”返回类型。但也许其他人可以澄清这一点。一个简洁的替代方案,但它只是呼喊着不可维护性。尽管如此,我还是很感激!为什么无法维护?在我看来,这是一个松散的适合,而不是依赖于特性。您所指定的只是传入(或混合)对象支持特定的操作,而不是它存在于特定的类层次结构上。例如,昆虫
和鸟
可能都生活在同一层次结构上,飞机
不会,但它们都支持飞行
方法。这取决于你的实际需求。一个简洁的替代方案,但它只是呼喊着不可维护性。尽管如此,我还是很感激!为什么无法维护?在我看来,这是一个松散的适合,而不是依赖于特性。您所指定的只是传入(或混合)对象支持特定的操作,而不是它存在于特定的类层次结构上。例如,昆虫
和鸟
可能都生活在同一层次结构上,飞机
不会,但它们都支持飞行
方法。这取决于你的实际需求。