You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 07:32:33