Kotlin实现父类方法返回调用它的子类实例的问题
问题:让继承类的方法返回自身类型而非父类类型
问题描述
我有一个Quadrilateral类,继承自父类Polygon的translate方法,Polygon实现了Shape接口。当前Polygon的translate方法返回Polygon实例,但Quadrilateral有自己的特有方法,调用Quadrilateral实例的translate后,无法直接调用这些特有方法。
实际场景存在更深的继承结构(比如Square或Rectangle继承自Quadrilateral),我希望在父类中仅实现一次这类方法,但调用时始终返回调用该方法的子类的新实例。
尝试用泛型+强制类型转换实现时,遇到如下异常:
Exception in thread "main" java.lang.ClassCastException: class Polygon cannot be cast to class Quadrilateral (Polygon and Quadrilateral are in unnamed module of loader 'app') at MainKt.main(Main.kt:10)
基础示例代码(无法运行)
interface Shape { fun translate(translation: Double): Shape } open class Polygon(open val vertices: List<Pair<Double, Double>>) : Shape { override fun translate(translation: Double): Polygon { return Polygon(vertices.map { Pair(it.first + translation, it.second + translation) }) } } class Quadrilateral(override val vertices: List<Pair<Double, Double>>) : Polygon(vertices) { fun scale(factor: Double): Quadrilateral { return Quadrilateral(vertices.map { Pair(it.first * factor, it.second * factor) }) } } fun main(args: Array<String>) { val a = Pair(0.0, 0.0) val b = Pair(0.1, 0.0) val c = Pair(1.0, 1.0) val d = Pair(0.0, 1.0) val rect = Quadrilateral(listOf(a, b, c, d)) // 编译报错:Polygon没有scale方法 println(rect.translate(5.0).scale(5.0)) }
泛型尝试代码
interface Shape<T: Shape<T>> { fun translate(translation: Double): T } open class Polygon<T : Polygon<T>>(open val vertices: List<Pair<Double, Double>>) : Shape<T> { override fun translate(translation: Double): T { // 强制转换导致ClassCastException return Polygon(vertices.map { Pair(it.first + translation, it.second + translation) }) as T } } class Quadrilateral(override val vertices: List<Pair<Double, Double>>) : Polygon<Quadrilateral>(vertices) { fun scale(factor: Double): Quadrilateral { return Quadrilateral(vertices.map { Pair(it.first * factor, it.second * factor) }) } } fun main(args: Array<String>) { val a = Pair(0.0, 0.0) val b = Pair(0.1, 0.0) val c = Pair(1.0, 1.0) val d = Pair(0.0, 1.0) val rect = Quadrilateral(listOf(a, b, c, d)) println(rect.translate(5.0).scale(5.0)) }
可行解决方案:抽象工厂方法+泛型
核心思路是让父类定义抽象的实例创建方法,由子类实现自身实例的创建逻辑,父类的业务方法(比如translate)调用该方法生成实例,避免强制类型转换。
修改后的代码:
interface Shape<T : Shape<T>> { fun translate(translation: Double): T } // 改为抽象类,新增抽象方法让子类实现实例创建 open abstract class Polygon<T : Polygon<T>>(open val vertices: List<Pair<Double, Double>>) : Shape<T> { // 子类必须实现:用新顶点创建自身实例 protected abstract fun createNewInstance(vertices: List<Pair<Double, Double>>): T override fun translate(translation: Double): T { val translatedVertices = vertices.map { Pair(it.first + translation, it.second + translation) } // 调用子类的实例创建方法 return createNewInstance(translatedVertices) } } class Quadrilateral(override val vertices: List<Pair<Double, Double>>) : Polygon<Quadrilateral>(vertices) { override fun createNewInstance(vertices: List<Pair<Double, Double>>): Quadrilateral { return Quadrilateral(vertices) } fun scale(factor: Double): Quadrilateral { val scaledVertices = vertices.map { Pair(it.first * factor, it.second * factor) } return createNewInstance(scaledVertices) } } // 更深层次的子类示例:Rectangle class Rectangle(val width: Double, val height: Double, vertices: List<Pair<Double, Double>>) : Polygon<Rectangle>(vertices) { override fun createNewInstance(vertices: List<Pair<Double, Double>>): Rectangle { // 可根据需求重新计算宽高,这里直接复用原有宽高示例 return Rectangle(width, height, vertices) } fun getArea(): Double { return width * height } } fun main(args: Array<String>) { val a = Pair(0.0, 0.0) val b = Pair(0.1, 0.0) val c = Pair(1.0, 1.0) val d = Pair(0.0, 1.0) val rect = Quadrilateral(listOf(a, b, c, d)) // 现在可以链式调用translate和scale println(rect.translate(5.0).scale(5.0).vertices) val rectangle = Rectangle(1.0, 1.0, listOf(a, Pair(1.0,0.0), Pair(1.0,1.0), d)) // Rectangle调用translate后仍可调用自身方法getArea println(rectangle.translate(2.0).getArea()) }
方案优势
- 父类仅需实现一次业务逻辑(比如
translate的顶点计算),子类无需重复编写 - 避免了不安全的强制类型转换,消除
ClassCastException - 支持任意深度的继承结构,子类只需实现
createNewInstance即可保证方法返回自身类型 - 符合开闭原则,新增子类时无需修改父类代码
内容的提问来源于stack exchange,提问作者Peanut
相关产品推荐
相关产品推荐

