Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/unix/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
&引用;几乎是一个;Scala中的关系_Scala_Mixins - Fatal编程技术网

&引用;几乎是一个;Scala中的关系

&引用;几乎是一个;Scala中的关系,scala,mixins,Scala,Mixins,我正在尝试设计一个类层次结构,其中包含一组类似的类,它们并不完全共享“是a”关系。让我们把这些类称为Model类。这些类意味着与使用模型类但不具有相同要求的类似算法集合配对。让我们把这些称为策略类。诀窍在于策略类需要从模型类中获得许多相同的东西,但并非所有模型类都能够实现这些所需的方法。我不想让空的“存根”方法只抛出UnsupportedOperationExceptions,而是用一种基于类型安全的mixin方法来处理这个问题——我可以应用一种设计模式吗 比如说, object Main ex

我正在尝试设计一个类层次结构,其中包含一组类似的类,它们并不完全共享“是a”关系。让我们把这些类称为
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
,以确保“最佳”返回类型。但也许其他人可以澄清这一点。一个简洁的替代方案,但它只是呼喊着不可维护性。尽管如此,我还是很感激!为什么无法维护?在我看来,这是一个松散的适合,而不是依赖于特性。您所指定的只是传入(或混合)对象支持特定的操作,而不是它存在于特定的类层次结构上。例如,
昆虫
可能都生活在同一层次结构上,
飞机
不会,但它们都支持
飞行
方法。这取决于你的实际需求。一个简洁的替代方案,但它只是呼喊着不可维护性。尽管如此,我还是很感激!为什么无法维护?在我看来,这是一个松散的适合,而不是依赖于特性。您所指定的只是传入(或混合)对象支持特定的操作,而不是它存在于特定的类层次结构上。例如,
昆虫
可能都生活在同一层次结构上,
飞机
不会,但它们都支持
飞行
方法。这取决于你的实际需求。