如何为Measurement子类实现unaryMinus()以创建自身类负实例?
实现通用的Measurement子类一元负号运算符
这个需求太常见了——想让父类的一元负号运算符自动适配所有子类,不用每个子类都重复写一遍逻辑对吧?我之前做单位转换类的时候也碰到过,给你几个靠谱的方案,看你用的语言选就行:
方案1:利用自类型(Self Type)(推荐,适合Swift/Kotlin等支持的语言)
如果你的编程语言支持Self类型(比如Swift、Kotlin),这是最简洁优雅的方案。父类直接实现一元负号运算符,返回Self类型,利用子类的构造器创建实例:
Swift示例代码
class Measurement { var value: Double init(value: Double) { self.value = value } // 核心:返回当前子类的类型(Self),复用子类的构造逻辑 static prefix func - (instance: Self) -> Self { return Self(value: -instance.value) } } // 子类只需继承,无需重写运算符 class Length: Measurement {} class Inches: Length {} class Degrees: Measurement {} // 测试效果 let fiveInches = Inches(value: 5) let negativeFive = -fiveInches print(type(of: negativeFive)) // 输出:Inches print(negativeFive.value) // 输出:-5.0 let thirtyDegrees = Degrees(value: 30) let negativeThirty = -thirtyDegrees print(type(of: negativeThirty)) // 输出:Degrees
方案2:模板方法模式+泛型(适合Java等不支持Self的语言)
对于Java这类不支持自类型的语言,可以用模板方法模式结合泛型,让子类提供创建自身实例的逻辑,父类统一处理一元负号的计算:
Java示例代码
// 父类用泛型约束为自身子类 abstract class Measurement<T extends Measurement<T>> { protected double value; protected Measurement(double value) { this.value = value; } // 子类必须实现:创建当前子类的实例 protected abstract T createInstance(double value); // 父类统一实现一元负号逻辑 public T unaryMinus() { return createInstance(-this.value); } } class Length extends Measurement<Length> { public Length(double value) { super(value); } @Override protected Length createInstance(double value) { return new Length(value); } } class Inches extends Length { public Inches(double value) { super(value); } @Override protected Inches createInstance(double value) { return new Inches(value); } } class Degrees extends Measurement<Degrees> { public Degrees(double value) { super(value); } @Override protected Degrees createInstance(double value) { return new Degrees(value); } } // 测试 public class Main { public static void main(String[] args) { Inches five = new Inches(5); Inches negativeFive = five.unaryMinus(); System.out.println(negativeFive.value); // 输出:-5.0 Degrees thirty = new Degrees(30); Degrees negativeThirty = thirty.unaryMinus(); System.out.println(negativeThirty.value); // 输出:-30.0 } }
方案3:反射实现(最省事,但牺牲类型安全)
如果想完全不用子类写额外代码,可以用反射在父类中动态创建子类实例。缺点是性能稍差,且要求所有子类都有相同参数的构造器:
Java反射示例代码
class Measurement { protected double value; public Measurement(double value) { this.value = value; } public Measurement unaryMinus() { try { // 获取当前实例的类,调用double参数的构造器创建新实例 return this.getClass().getConstructor(double.class).newInstance(-this.value); } catch (Exception e) { throw new RuntimeException("所有子类必须提供double参数的构造器", e); } } } // 子类直接继承,无需额外实现 class Inches extends Measurement { public Inches(double value) { super(value); } } class Degrees extends Measurement { public Degrees(double value) { super(value); } }
总结
- 优先选自类型方案,代码最简洁,类型安全;
- 若语言不支持自类型,用模板方法+泛型,虽然子类要多写一行,但类型安全可控;
- 反射方案适合快速原型,或者所有子类构造器统一的场景,但要注意异常处理。
内容的提问来源于stack exchange,提问作者Aanand Kainth
相关产品推荐
相关产品推荐

