题
我有一些类与相同的超类型。因此,所有这班有覆盖同样的方法。现在我可以调用一个方法并提交通用超类型的对象。但它并不总是有用的,以每个提交的类型,因此抛出一个异常反应。首先,我试图解决此问题是这样的:
def operation(s: SuperType) = s match {
case t: SubType1 => ...
case t: SubType2 => ...
case _ => ...
}
由于大量的子类型,这将导致对大量的代码(在每个方法和每个类中),我试图解决这个问题与traits
。每个性状应该测试仅一种类型,然后将对象转发到堆栈上的更高的方法。下面的代码描述我是如何想象。但是,这不工作,因为编译器无法溶解的类型。另一问题是,我要声明的类的各属性中的每个行为类。
object TraitWithTest {
def main(args: Array[String]) {
val e1 = Even(2, 4)
val e2 = Even(1, 3)
val o1 = Odd(1.25, 3.75)
val o2 = Odd(7.25, 9.25)
val a1 = All(5.5)
val a2 = All(3.5)
println("e1 + e2: " + (e1 + e2))
println("o1 + o2: " + (o1 + o2))
try { println("e1 + o2: " + (e1 + o2)) } catch { case e => println(e) }
println("o1 + e2: " + (o1 + e2))
println("a1 + e1: " + (a1 + e2))
}
}
abstract class Num {
def +(n: Num): Num
}
trait OddBehaviour extends Num {
val e1, e2: Int // here I don't want to declare all attributes
val a1: Double
abstract override def +(n: Num) = n match {
case o: Odd => throw new UnsupportedOperationException("Even#+(Odd)")
case _ => super.+(n)
}
}
trait EvenBehaviour extends Num {
val o1, o2: Double
val a1: Double
abstract override def +(n: Num) = n match {
case e: Even => Odd(o1 + e.e1, o2 + e.e2)
case _ => super.+(n)
}
}
trait AllBehaviour extends Num {
val o1, o2: Double
val e1, e2: Int
abstract override def +(n: Num) = n match {
case a: All => Odd(o1 + a.a1, o2 + a.a1)
case _ => super.+(n)
}
}
object Even {
def apply(e1: Int, e2: Int) = new Even(e1, e2) with OddBehaviour with AllBehaviour
}
abstract case class Even(e1: Int, e2: Int) extends Num {
override def +(n: Num) = n match {
case c: Even => Even(e1 + c.e1, e2 + c.e2)
case _ => throw new IllegalArgumentException
}
}
object Odd {
def apply(o1: Double, o2: Double) = new Odd(o1, o2) with EvenBehaviour with AllBehaviour
}
abstract case class Odd(o1: Double, o2: Double) extends Num {
override def +(n: Num) = n match {
case o: Odd => Odd(o1 + o.o1, o2 + o.o2)
case _ => throw new IllegalArgumentException
}
}
object All {
def apply(a1: Double) = new All(a1) with EvenBehaviour with OddBehaviour
}
abstract case class All(a1: Double) extends Num {
override def +(n: Num) = n match {
case a: All => All(a1 + a.a1)
case _ => throw new IllegalArgumentException
}
}
可以有人给我说是否可以通过使用特性,以减少行代码?或者是我目前使用的最好的比赛,所有的解决方案?
修改强>
在您的帮助,我发现一个半工作解决方案。我的主问题是,我试图通过使用斯卡拉的功能,以减少代码的行数。所以,我忽略了最简单的方法:外包的代码!我只需要创建一个新的对象,检查对象的组合。本身仅处理其自己的类型的对象。
这是代码:
final object TraitWithTest {
def main(args: Array[String]) {
import traitwith.operations._
val e1 = Even(2, 4)
val e2 = Even(1, 3)
val o1 = Odd(1.25, 3.75)
val o2 = Odd(7.25, 9.25)
val a1 = All(5.5)
val a2 = All(3.5)
val n1 = NumHolder(o1)
val n2 = NumHolder(a1)
println("e1 + e2: " + add(e1, e2))
println("o1 + o2: " + add(o1, o2))
try { println("e1 + o2: " + add(e1, o2)) } catch { case e => println(e) }
println("o1 + e2: " + add(o1, e2))
try { println("a1 + e2: " + add(a1, e2)) } catch { case e => println(e) }
println("n1 + n2: " + add(n1, n2))
}
}
final object operations {
def add(a: Num, b: Num) = a -> b match {
case (a1: Odd, b1: Odd) => a1 + b1
case (a1: Odd, b1: Even) => Odd(a1.x + b1.x, a1.y + b1.y)
case (a1: Odd, b1: All) => Odd(a1.x + b1.x, a1.y + b1.x)
case (a1: Even, b1: Even) => a1 + b1
case (a1: All, b1: All) => a1 + b1
case _ => error("can't add " + b + " to " + a)
}
}
abstract class Num {
type A <: Num
def +(a: A): A
}
final case class Odd(x: Double, y: Double) extends Num {
override type A = Odd
override def +(a: Odd) = Odd(x + a.x, y + a.y)
}
final case class Even(x: Int, y: Int) extends Num {
override type A = Even
override def +(a: Even) = Even(x + a.x, y + a.y)
}
final case class All(x: Double) extends Num {
override type A = All
override def +(a: All) = All(x + a.x)
}
final case class NumHolder(x: Num) extends Num {
override type A = NumHolder
override def +(a: NumHolder) = NumHolder(x + a.x)
}
我扩展代码中的位和插入的对象NumHolder
。现在,只有一个小缺陷:没有附加方法得到一个编译错误,在NumHolder我不能承诺超强型。我试图使用代替类型关键字泛型但是这是不方便,因为我有总是设置类型NUM(也是在对象的操作)。
我该如何解决这个小编译错误?
解决方案 6
基于凯文·莱特答案一>我现在解决了这个问题:
package de.traitwith
import de.traitwith.Operations._
import de.traitwith._
object TraitWithTest {
def main(args: Array[String]) {
val e1 = Even(2, 4)
val e2 = Even(1, 3)
val o1 = Odd(1.25, 3.75)
val o2 = Odd(7.25, 9.25)
val a1 = All(5.5)
val a2 = All(3.5)
val n1 = NumHolder(o1)
val n2 = NumHolder(a1)
println("e1 + e2: " + add(e1, e2))
println("o1 + o2: " + add(o1, o2))
try { println("e1 + o2: " + add(e1, o2)) } catch { case e => println(e) }
println("o1 + e2: " + add(o1, e2))
try { println("a1 + e2: " + add(a1, e2)) } catch { case e => println(e) }
println("n1 + n2: " + add(n1, n2))
println("o1 + n2: " + add(o1, n2))
}
}
object Operations {
def add(a: Num, b: Num): Num = a -> b match {
case (a1: Odd, b1: Odd) => a1 + b1
case (a1: Odd, b1: Even) => Odd(a1.x + b1.x, a1.y + b1.y)
case (a1: Odd, b1: All) => Odd(a1.x + b1.x, a1.y + b1.x)
case (a1: Odd, b1: NumHolder) => add(a1, b1.x)
case (a1: Even, b1: Even) => a1 + b1
case (a1: Even, b1: NumHolder) => add(a1, b1.x)
case (a1: All, b1: All) => a1 + b1
case (a1: All, b1: NumHolder) => add(a1, b1.x)
case (a1: NumHolder, b1: NumHolder) => a1 + b1
case (a1: NumHolder, b1: Odd)=> add(a1.x, b1)
case (a1: NumHolder, b1: Even) => add(a1.x, b1)
case (a1: NumHolder, b1: All) => add(a1.x, b1)
case _ => error("can't add " + b + " to " + a)
}
}
abstract class Num
final case class Odd(x: Double, y: Double) extends Num {
def +(a: Odd) = Odd(x + a.x, y + a.y)
}
final case class Even(x: Int, y: Int) extends Num {
def +(a: Even) = Even(x + a.x, y + a.y)
}
final case class All(x: Double) extends Num {
def +(a: All) = All(x + a.x)
}
final case class NumHolder(x: Num) extends Num {
def +(a: NumHolder) = NumHolder(add(x, a.x))
}
我不具备超强型更多的一些方法 - 我希望,同一天,这不会造成问题。这是可以删除的类,但我在实际应用中我有更大的类,所以我需要他们所有加载方法那里。
其他提示
您的问题是,你要使用面向对象的特性,如类和继承,与是不是面向对象的设计。
在整个的点的OOP的是,你不反思什么是类。使用,相反,多态性达到的结果。我特别喜欢在说明OO应该是怎样本文的工作,但不存在资源短缺在那里在这方面
修改强>
例如,大致提供的代码转换成下面,减去不工作的事情(提供的代码不编译因为它们的精确)。
abstract class Num {
def +(n: Num): Num
def plus(n1: Int, n2: Int): Num
def plus(n1: Double, n2: Double): Num
def plus(n: Double): Num
}
case class Even(e1: Int, e2: Int) extends Num {
override def +(n: Num) = n.plus(e1, e2)
override def plus(n1: Int, n2: Int) = Even(e1 + n1, e2 + n2)
override def plus(n1: Double, n2: Double) = Odd(n1 + e1, n2 + e2)
// the code provided references o1 and o2, which are not defined anywhere for Even
// so I'm providing an alternate version
override def plus(n: Double) = Odd(n + e1, n + e2)
}
case class Odd(o1: Double, o2: Double) extends Num {
override def +(n: Num) = n.plus(o1, o2)
override def plus(n1: Int, n2: Int) = throw new UnsupportedOperationException("Even#+(Odd)")
override def plus(n1: Double, n2: Double) = Odd(o1 + n1, o2 + n2)
override def plus(n: Double) = throw new UnsupportedOperationException("Even#+(Odd)")
}
case class All(a1: Double) extends Num {
override def +(n: Num) = n.plus(a1)
// the code provided references o1 and o2, which are not defined anywhere for All
// so I'm providing an alternate version
override def plus(n1: Int, n2: Int) = Odd(a1 + n1, a1 + n2)
override def plus(n1: Double, n2: Double) = Odd(n1 + a1, n2 + a1)
override def plus(n: Double) = All(a1 + n)
}
在我看来它可以与访问者模式,这是有意义的进一步提高,因为它靶向相同的问题,类型匹配通常不会
要错误引用特定广告:有该...
一类型的类斯卡拉已经支持通过 “数字” 特设多态通过Numeric
,这可能是你的真的想:的 http://www.scala-lang.org/archives/downloads/distrib/files/nightly/docs /library/scala/math/Numeric.html
但是,如果这个偶/奇/所有的方案是你实际上在做什么,而不是只是一个人为的例子,那么你可以随时推出自己的类型的类!
让我们把它Addable
:
case class Even(x:Int, y:Int)
case class Odd(x:Double, y:Double)
case class All(x:Double)
abstract class Addable[A, B] {
def add(a: A, b: B): A
}
implicit object EvenCanAddEven extends Addable[Even, Even] {
def add(a:Even, b:Even) = Even(a.x+b.x, a.y+b.y)
}
implicit object OddCanAddOdd extends Addable[Odd, Odd] {
def add(a:Odd, b:Odd) = Odd(a.x+b.x, a.y+b.y)
}
implicit object OddCanAddEven extends Addable[Odd, Even] {
def add(a:Odd, b:Even) = Odd(a.x+b.x, a.y+b.y)
}
implicit object AllCanAddAll extends Addable[All, All] {
def add(a:All, b:All) = All(a.x+b.x)
}
def add[A,B](a:A, b:B)(implicit tc: Addable[A,B]) =
tc.add(a, b)
val e1 = Even(2, 4)
val e2 = Even(1, 3)
val o1 = Odd(1.25, 3.75)
val o2 = Odd(7.25, 9.25)
val a1 = All(5.5)
val a2 = All(3.5)
println("e1 + e2: " + add(e1, e2))
println("o1 + o2: " + add(o1, o2))
println("e1 + o2: " + add(e1, o2)) //compiler should fail this line
println("o1 + e2: " + add(o1, e2))
println("a1 + e1: " + add(a1, e2))
<强>声明:强> 我没有实际测试的代码,此机器不(还)具有安装的Scala
的备选解决方案中,当类型是未知的,直到运行时间:
sealed trait Num
case class Even(x:Int, y:Int) extends Num
case class Odd(x:Double, y:Double) extends Num
case class All(x:Double) extends Num
object operations {
def add(a: Num, b: Num) : Num = (a,b) match {
case (a1:Even, b1:Even) => Even(a1.x+b1.x, a1.y+b1.y)
case (a1:Odd, b1:Odd) => Odd(a1.x+b1.x, a1.y+b1.y)
case (a1:Odd, b1:Even) => Odd(a1.x+b1.x, a1.y+b1.y)
case (a1:All, b1:All) => All(a1.x, b1.x)
case _ => error("can't add " + a + " to " + b)
}
}
这里的关键是要既PARAMS第一包装成一个元组,那么你就必须在一个单一对象到模式匹配。
<强>更新强>
随着你的编辑;你似乎并不需要抽象类型A
任何地方,为什么不见好就收Num
作为标记性状和在每个子类中单独定义方法+?
sealed abstract trait Num
case class Odd(x: Double, y: Double) extends Num {
def +(a: Odd) = Odd(x + a.x, y + a.y)
}
final case class Even(x: Int, y: Int) extends Num {
def +(a: Even) = Even(x + a.x, y + a.y)
}
final case class All(x: Double) extends Num {
def +(a: All) = All(x + a.x)
}
final case class NumHolder(x: Num) extends Num {
def +(a: NumHolder) = NumHolder(x + a.x)
}
我不知道如果我能解决你的问题,但同时它的思想我想至少让你的榜样编译和工作,这是希望至少有点帮助。
我已经添加在toString
方法的形式的一些噪声,以便能够看到实例和表达的结果。
abstract class Num(val a: Double, val b: Double) {
def +(that: Num): Num
override def toString = (<z>Num({a}, {b})</z> text)
}
在“不得已而为之”类,All
,应该是一个case类,使配套更平滑,但因为它会被继承为真实案例类将无法正常工作。与apply
和unapply
方法解决了伴随对象。
这是All
可以处理类似的术语,但并不试图手柄Even
和Odd
方面,因为这些术语是偷偷同时All
s。
class All(override val a: Double, override val b: Double) extends Num(a, b) {
def +(that: Num): Num = that match {
case All(n) => All(this.a + n)
case _ => error("I don't know this subtype")
}
override def toString = (<z>All({a})</z> text)
}
object All {
def apply(num: Double) = new All(num, num)
def unapply(num: All) = Some(num.a)
}
现在,一路Even
s和Odd
s工作可以提炼成特性,但没有必要在这个例子。不这样做简化了继承,但可能违背的例子来看,我不知道。
这是Even
知道如何处理Even
和Odd
方面,而是将他人进行其超。再次,这是用于匹配目的的人造情况类。
class Even(override val a: Double, override val b: Double) extends All(a, b) {
override def +(that: Num): Num = that match {
case Even(a, b) => Even(this.a + a, this.b + b)
case Odd(a, b) => Odd(this.a + a, this.b + b)
case x => super.+(x)
}
override def toString = (<z>Even({a}, {b})</z> text)
}
object Even {
def apply(a: Double, b: Double) = new Even(a, b)
def unapply(num: Even) = Some((num.a, num.b))
}
这是Odd
知道如何处理Even
条款,但拒绝处理Odd
的人(我改变了这个从您的例子做一个弱双关语,欢迎您)。
class Odd(override val a: Double, override val b: Double) extends All(a, b) {
override def +(that: Num): Num = that match {
case Even(a, b) => Odd(this.a + a, this.b + b)
case Odd(a, b) => error("Adding two Odds is an odd thing to do")
case x => super.+(x)
}
override def toString = (<z>Odd({a}, {b})</z> text)
}
object Odd {
def apply(a: Double, b: Double) = new Odd(a, b)
def unapply(num: Odd) = Some((num.a, num.b))
}
行,让我们采取一自旋。
object Try {
def main(args: Array[String]) {
val e1 = Even(2, 4)
val e2 = Even(1, 3)
val o1 = Odd(1.25, 3.75)
val o2 = Odd(7.25, 9.25)
val a1 = All(5.5)
val a2 = All(3.5)
println("e1 + e2: " + (e1 + e2))
println("e1 + o2: " + (e1 + o2))
try { println("o1 + o2: " + (o1 + o2)) } catch { case e => println(e) }
println("o1 + e2: " + (o1 + e2))
println("a1 + e1: " + (a1 + e2))
}
}
它看起来像仿制药可能会帮助你。尝试是这样的:
class Supertype[A <: Supertype] {
def operation(s: A) {
}
}
class Subtype extends SuperType[Subtype] {
override def operation(s: Subtype) {
}
}
您的问题描述不是很清楚,所以这是一个猜测...