如何设计不同种类的(几乎)相同的(在Scala中)

时间:2019-11-25 08:13:46

标签: scala generics design-patterns .obj wavefront

我在Scala中遇到以下问题...

我想读取wavefront文件(.obj)并将其转换为以后可以使用的文件。 我要支持的wavefront文件是具有以下定义的文件:

  • TypeA:顶点和面
  • TypeB:顶点,纹理和面
  • TypeC:顶点,法线和面
  • TypeD:顶点,纹理,法线和面

我将阅读它们并使用以下字段为其创建一个Mesh(模型类,供以后使用):

  • TypeA:Array[Float]Array[Int]
  • TypeB:Array[Float]Array[Float]Array[Int]
  • TypeC:Array[Float]Array[Float]Array[Int]
  • TypeD:Array[Float]Array[Float]Array[Float]Array[Int]

我发现了两种方法:

1。方法:

每种类型都有自己的模型类

  • TypeA:case class TypeA(vertices: Array[Float], index: Array[Float])
  • TypeB:case class TypeB(vertices: Array[Float], textures: Array[Float], index: Array[Float])
  • TypeC:case class TypeC(vertices: Array[Float], normals: Array[Float], index: Array[Float])
  • TypeD:case class TypeD(vertices: Array[Float], textures: Array[Float], normals: Array[Float], index: Array[Float])

使用这种方法,我不必检查是否所有字段都存在。我可以直接使用它们。缺点是:我需要为每种类型创建“构建”方法(类似:createTypeAFromFile(filename: String)

2。方法 我创建了一个超级模型:

case class Mesh(vertices: Array[Float], textures: Option[Array[Float]], normals: Option[Array[Float]], index: Array[Float])

使用这种方法,我只需要一个“构建”方法,但是这里的问题是,稍后我必须检查我要使用的字段是否真的存在(用于法线和纹理)

问题:

有人针对这种问题知道更好的方法/设计吗?

2 个答案:

答案 0 :(得分:2)

如果您知道要对这些类型执行的操作通常会有所帮助,一个不错的博客文章是:https://www.sandimetz.com/blog/2016/1/20/the-wrong-abstraction,其中作者认为错误的抽象比重复一些要糟得多。

采用方法1,也许为所有这些方法创建一个特征,您将看到是否可以将它们分组为类型,是否值得。

答案 1 :(得分:2)

[感谢@simpadjo更新]

方法3是创建一个特征层次结构来表示不同的选项:

trait Faces {
  def vertices: Array[Float]
  def faces: Array[Float]
}
trait Textures extends Faces {
  def textures: Array[Float]
}
trait Normals extends Faces {
  def normals: Array[Float]
}
trait Obj3D extends Textures with Normals 

class A(
  val vertices: Array[Float],
  val faces: Array[Float]
) extends Faces

class B(
  val vertices: Array[Float],
  val textures: Array[Float],
  val faces: Array[Float]
) extends Textures

class C(
  val vertices: Array[Float],
  val normals: Array[Float],
  val faces: Array[Float]
) extends Normals

class D(
  val vertices: Array[Float],
  val textures: Array[Float],
  val normals: Array[Float],
  val faces: Array[Float]
) extends Obj3D

解析器可以返回Faces,但如果有其他字段可用,它将创建适当的子类。然后,您可以创建Mesh中的Faces,但是使用match来检测是否有附加信息可用。