Kotlin中如何实现运算符继承?解决物理量类代码重复问题
解决Kotlin中物理量类的运算符代码复用问题
你的问题核心是要在多个拥有相同逻辑的类中复用运算符实现,同时保持返回具体子类类型的能力——直接用无泛型的接口/抽象类会因为返回类型不匹配卡壳,这里用泛型绑定自身类型的方案就能完美解决。
方案一:泛型抽象类(推荐,更适合有状态的类)
我们可以定义一个带泛型的抽象类,泛型参数约束为子类自身类型,这样所有通用运算符都可以在抽象类中实现,返回具体的子类类型:
abstract class PhysicalQuantity<T : PhysicalQuantity<T>>(var value: Double) { // 自增运算符:修改当前实例的value并返回自身(具体子类类型) operator fun inc(): T { value++ return this as T } // 同类型加法:当前实例加上另一个同类型实例的value operator fun plus(other: T): T { value += other.value return this as T } // 同理可以实现自减、减法等通用运算符 operator fun dec(): T { value-- return this as T } } // Volume类继承抽象类,指定泛型参数为自身 class Volume(value: Double, unit: Unit) : PhysicalQuantity<Volume>(value) { var unit: Unit = unit private set enum class Unit(symbol: String){ MILLILITER("ml"), CENTILITER("cl"), DECILITER("dl"), LITER("l"), TEASPOON("tsp"), TABLESPOON("tbsp"), FLUIDOUNCE("floz"), SHOT("jig"), GILL("gi"), CUP("cup"), PINT("pt"), QUART("qt"), GALLON("gal") } } // Mass类同样继承,指定泛型参数为自身 class Mass(value: Double, unit: Unit) : PhysicalQuantity<Mass>(value) { var unit: Unit = unit private set enum class Unit(symbol: String){ GRAM("g"), DECAGRAM("dag"), HECTOGRAM("hg"), KILOGRAM("kg"), OUNCE("oz"), POUND("lb") } }
方案二:泛型接口(适合更灵活的场景)
如果不想用抽象类,也可以用带泛型的接口,利用Kotlin的接口默认方法实现复用:
interface PhysicalQuantity<T : PhysicalQuantity<T>> { var value: Double operator fun inc(): T { value++ return this as T } operator fun plus(other: T): T { value += other.value return this as T } } class Volume(override var value: Double, unit: Unit) : PhysicalQuantity<Volume> { var unit: Unit = unit private set // 枚举类不变 } class Mass(override var value: Double, unit: Unit) : PhysicalQuantity<Mass> { var unit: Unit = unit private set // 枚举类不变 }
为什么这个方案能解决问题?
- 泛型绑定自身:通过
T : PhysicalQuantity<T>的约束,我们告诉编译器T必须是继承自PhysicalQuantity的子类,而且就是当前类自己。 - 安全的类型转换:
this as T是完全安全的,因为子类继承时明确指定了T为自身类型(比如Volume的T就是Volume),不会出现类型转换异常。 - 代码完全复用:所有通用运算符的逻辑都只写一次,子类不需要重复实现,直接继承即可,同时返回的是具体的子类类型,符合你的需求。
额外提示
如果你的运算符需要创建新实例(而不是修改当前实例),比如加法返回一个新的Volume而不是修改原对象,那么可以在抽象类中定义一个抽象方法来创建实例,比如:
abstract class PhysicalQuantity<T : PhysicalQuantity<T>>(var value: Double) { protected abstract fun createNew(value: Double): T operator fun plus(other: T): T { return createNew(this.value + other.value) } } // 在Volume中实现createNew class Volume(value: Double, val unit: Unit) : PhysicalQuantity<Volume>(value) { override fun createNew(value: Double): Volume { return Volume(value, this.unit) } }
这样就能实现无副作用的算术运算,同时依然复用大部分代码。
内容的提问来源于stack exchange,提问作者Peter
相关产品推荐
相关产品推荐

