I have a calculation program which uses a number of different vertex types. Currently I have euclidean and geo, and I have decided to create an interface. Now I am wondering if that is a good idea.
interface Vertex: Comparable<Vertex> {
var id: Int
/** returns then distance to another vertex. Vertex is expected to be of exact same type */
fun distanceTo(vertex: Vertex): Double
override fun compareTo(other: Vertex): Int {
return id.compareTo(other.id)
}
}
class Vertex2d(override var id: Int, val x: Double, val y: Double) : Vertex {
override fun distanceTo(vertex: Vertex): Double {
vertex as Vertex2d
val distX: Double = x - vertex.x
val distY: Double = y - vertex.y
return (sqrt(distX * distX + distY * distY) * 100000.0).roundToInt() / 100000.0 // hypot takes 3 times as long
}
}
class VertexGeo(override var id: Int, val latitudeRadians: Double, val longitudeRadians: Double) : Vertex {
override fun distanceTo(vertex: Vertex): Double {
vertex as VertexGeo
// some complex calculation
return distance
}
}
The issue is, I always need a cast in distanceTo and this only work if the type is correct. I should actually check additionally isInstanceof, but no need in my progam.
Since the calculation is run billions of times (actually faster than storing the result in a memory table) performance is also an issue, but do not weigh is too much. Clean design is more a priority.
Instead I could do just one Vertex object with a type. Having the same signature I can use factory methods, but that is a minor detail.
enum class VertexType { EUC, GEO }
/**
* @param x: x in EUC or longitude in radians
*/
class VertexInOne(var id: Int, val x: Double, val y: Double, val type: VertexType): Comparable<VertexInOne> {
val latitudeRadians
get() = y
val longitudeRadians
get() = x
fun toDistance(other: VertexInOne) {
when (type) {
VertexType.EUC -> {
// calc distance
return distance
}
VertexType.GEO -> {
// calc distance
return distance
}
}
}
override fun compareTo(other: VertexInOne): Int {
return id.compareTo(other.id)
}
companion object {
fun createVertexEuc(id: Int, x: Double, y: Double): VertexInOne {
return VertexInOne(id, x, y, VertexType.EUC)
}
fun createVertexGeo(id: Int, latRadians: Double, longRadians: Double): VertexInOne {
return VertexInOne(id, longRadians, latRadians, VertexType.GEO)
}
}
}
What would be your choice and why?
Aucun commentaire:
Enregistrer un commentaire