适用于2D和3D矢量的类层次结构

dsg*_*dsg 5 architecture oop scala hierarchy

我想要一个通用的矢量抽象类/特征来指定某些方法,例如:

trait Vec 
{
  def +(v:Vec):Vec
  def *(d:Double):Vec

  def dot(v:Vec):Double
  def norm:Double
}
Run Code Online (Sandbox Code Playgroud)

我想拥有Vec2DVec3D扩展Vec:

class Vec2D extends Vec { /* implementation */ }
class Vec3D extends Vec { /* implementation */ }
Run Code Online (Sandbox Code Playgroud)

但是,我怎样才能使它Vec2D只能被添加到其他Vec2D而不是Vec3D

现在我只是实现Vec2D并且Vec3D没有共同的Vec祖先,但是重复代码变得乏味.我要实现依赖于这些类中的所有我的几何类(如Triangle,Polygon,Mesh,...)两次,一次Vec2D又一次的Vec3D.

我看到了java实现:javax.vecmath.Vector2djavax.vecmath.Vector3d没有共同的祖先.这是什么原因?有没有办法在scala中克服它?

Lan*_*dei 7

你可以使用自我类型:

trait Vec[T] { self:T =>
  def +(v:T):T
  def *(d:Double):T

  def dot(v:T):Double
  def norm:Double
}

class Vec2D extends Vec[Vec2D] { /* implementation */ }
class Vec3D extends Vec[Vec3D] { /* implementation */ }
Run Code Online (Sandbox Code Playgroud)

但如果两个实现非常相似,您也可以尝试在Dimension上进行抽象.

sealed trait Dimension
case object Dim2D extends Dimension
case object Dim3D extends Dimension

sealed abstract class Vec[D <: Dimension](val data: Array[Double]) { 

  def +(v:Vec[D]):Vec[D] = ...
  def *(d:Double):Vec[D] = ...

  def dot(v:Vec[D]):Double = ...
  def norm:Double = math.sqrt(data.map(x => x*x).sum)
}

class Vec2D(x:Double, y:Double) extends Vec[Dim2D.type](Array(x,y))
class Vec3D(x:Double, y:Double, z:Double) extends Vec[Dim3D.type](Array(x,y,z))
Run Code Online (Sandbox Code Playgroud)

当然,这取决于您希望如何表示数据,以及您是否希望拥有可变或不可变的实例.对于"真实世界"的应用程序,您应该考虑http://code.google.com/p/simplex3d/


Deb*_*ski 5

至于要求,设计基本特征的最有用的方法既涉及CRTP 自我类型的注释.

trait Vec[T <: Vec[T]] { this: T =>
  def -(v: T): T
  def *(d: Double): T

  def dot(v: T): Double
  def norm: Double = math.sqrt(this dot this)
  def dist(v: T) = (this - v).norm
}
Run Code Online (Sandbox Code Playgroud)

没有自我类型,就不可能this.dot(this)dot预期调用T; 因此我们需要使用注释强制执行它.

在另一方面,没有CRTP,我们就不能调用norm(this - v)-回报T,因此,我们需要确保我们的类型T有这种方法,如声明T 是一个 Vec[T].