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)
我想拥有Vec2D并Vec3D扩展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.Vector2d并javax.vecmath.Vector3d没有共同的祖先.这是什么原因?有没有办法在scala中克服它?
你可以使用自我类型:
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/
至于要求,设计基本特征的最有用的方法既涉及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].