如何保护自己免受参数错位的影响

时间:2017-06-30 08:49:43

标签: java

假设我有这个重要的方法:

int generateId(int clientCode, int dataVersion) {
    return clientCode * 2 + dataVersion % 2;
}

这两个参数都是int,因此使用错误的参数(例如generateId(dataVersion, clientCode))调用此方法非常容易。它将被成功编译和执行。但是生成的id将完全错误,这可能会导致严重的问题。

所以,我的问题是:有没有办法保护自己免受这种参数错位的影响?

现在我只想把它改成int包装类,如:

int generateId(@Nonnull ClientCode clientCode, @Nonnull Version version) {
    return clientCode.getValue() * 2 + version.getValue() % 2;
}

static class IntWrapper<T> {
    private final int value;

    IntWrapper(int value) {
        this.value = value;
    }

    public int getValue() {
        return value;
    }
}

static class ClientCode extends IntWrapper<ClientCode> {
    ClientCode(int value) {
        super(value);
    }
}

static class Version extends IntWrapper<Version> {
    Version(int value) {
        super(value);
    }
}

并使用generateId(new ClientCode(clientCode), new Version(version))调用它。当然,它不能保证完全的保护,但至少它以这种方式更透明。

有没有更好的/其他方式?

4 个答案:

答案 0 :(得分:6)

考虑通过Method-Chaining配置你的对象

configure().withDataVersion(dataVersion).withClientCode(clientCode).generateId(); 

虽然它使配置更加冗长,但阅读起来也更清晰。

DataVersion ClientCode - 信息可以移动到内部类中。 configure()启动内部类,withDataVersion(int)withClientCode(int)基本上是设置者。 generateId()将像今天一样构建并返回您的ID。

答案 1 :(得分:1)

为每个参数编写包装类,只是为了确保某人不会对参数的顺序混淆听起来非常极端,并且使用起来很麻烦。

如果clientCodedataVersion适合较小的数据类型,例如byteshort,则可以将其用于区分。如果这些值中的某些值具有指定的值范围(例如,从1到100.000),则在方法中使用编译时检查,如果提供的值不合适则抛出异常(如果调用者可能会发生这种情况)错位的参数)。

如果您添加更多int个参数,您的担忧就会更加合理。在这种情况下,只写一个包含所有参数的包装类:

public class Input {
    private int clientCode;
    private int version;
    //other parameters
    ..
    // getters and setters
}

通过使用显式getter和setter,您强制调用者关注提供的值。奖励 - 如果需要,您可以为某些参数添加默认值。方法签名现在是int generateId(Input input)

这是Joshua Bloch的Effective Java中记录的良好做法。

答案 2 :(得分:0)

你以正确的方式,进一步重构代码,制作高级ClientCode, VersionId类。移除int包装器。让Id了解如何生成版本,换句话说,在Id类中填充代码。

Id generateId(ClientCode code, Version version) {
    return new Id(code, version);
}

答案 3 :(得分:0)

正如Tom在注释中指出的那样,java没有办法避免这种问题。其他语言如python和scala支持命名参数来解决这个问题 虽然很好但没有必要。

Java依赖程序员正确理解和使用所有库。因此,应使用正确的文档注释并生成文档。

使用您建议的包装类的另一种方法是使代码繁琐且难以理解。更不用说添加额外的代码行了。

结论:依靠程序员的知识,并生成文档。不要使用包装类。因为这是java社区中广泛使用的方法。