繁体   English   中英

如何防止在同一个 class 中直接访问 getter/setter 之外的私有成员?

[英]How to prevent direct access to private members outside of getters/setters in the same class?

挑战

给定一个 class 具有非平凡的 getter 和一些其他内部方法访问相同的private成员字段:

有效示例

class TestType {
    private String value;

    public String getValue() {
        return this.value == null || this.value.isEmpty() ? "default" : this.value;
    }

    public void setValue(String newValue) {
        this.value = newValue;
    }

    public int getValueLength() {
        return this.getValue().length();
    }
}

我想禁止在getValueLength()方法中绕过 getter。 getValueLength()的以下实现应该会产生某种错误(单元测试失败、checkstyle 错误或其他任何可以以通用方式自动化的错误):

方法无效

    public int getValueLength() {
        // ERROR: possible NullPointerException
        return this.value.length();
    }

背景

在我的实际代码中,getter 内部进行了一些延迟加载,仅在第一次访问时才加载实际值。 首先调用getValueLength()可能会直接导致NullPointerException或基于缺失值执行错误操作。

其动机是确保未来的开发人员不要忘记只使用 getter 方法而永远不会直接访问成员。 由于这是一个孤立的问题(即仅在专门添加这种延迟加载的情况下),如果需要一些额外的注释是可以接受的,例如在成员本身上,它应该只在选定的方法中访问,并且这些方法是标记为 - 或启用/禁用特定规则的特定检查样式注释。

只是把这个答案形成:

class LoadableVar<T> {

    private T val;
    private Supplier<T> loader;

    public LoadableVar(Supplier<? extends T> loader) {
        this.loader = loader;
    }

    public T get() {
        if (this.val == null) {
            //see: volatile and double-locking if multithreading
            this.val = this.loader.get();
        }
        return this.val;
    }

    public void set(T overwrite) { //WARN: ignores the loader!
        this.val = overwrite;
    }
}

然后,将其应用于您的 class:

class TestType {
    private final LoadableVar<String> value;

    public TestType() {
        //can also be passed into the class, or done however you desire
        this.value = new LoadableVar<>(() -> /* load string from i/o, etc */);
    }

    public String getValue() {
        return this.value.get();
    }

    public void setValue(String newValue) {
        this.value.set(newValue); //I don't think this should be settable, personally
    }

    public int getValueLength() {
        return this.getValue().length();
    }
}

现在,当您在 TestType 的 scope 中编写代码时:

String s;
s = this.value; //compile error!
s = this.getValue(); //OK
s = this.value.get(); //OK

如您所见,以这种方式执行此操作还使TestType#getValue变得多余,您可以简单地允许value成为protected的成员(在这种情况下,我将删除这些设置器并使其不可变)。

没有办法在代码中强制执行此操作。

但是,由于您在评论中提到“希望有某种方法可以通过某种工具来实现它”,并且该问题被标记为 ,我相信您可以创建一个自定义规则:

<module name="Regexp">
    <property name="id" value="valueField"/>
    <property name="format" value="\bvalue\b"/>
    <property name="illegalPattern" value="true"/>
    <property name="ignoreComments" value="true"/>
    <property name="message" value="Do not use 'value' field directly;  use getValue() instead."/>
</module>

然后你会想要禁止检查你自己的“有效”行:

<module name="SuppressWithNearbyCommentFilter">
    <property name="idFormat" value="valueField"/>
</module>

在代码中:

private String value;   // SUPPRESS CHECKSTYLE

public String getValue() {
    return this.value == null || this.value.isEmpty() ? "default" : this.value; // SUPPRESS CHECKSTYLE
}

public void setValue(String newValue) {
    this.value = newValue;  // SUPPRESS CHECKSTYLE
}

(还有其他方法可以通过注释来抑制 Checkstyle 的检查,您可能会发现它们在视觉上更令人愉悦。请参阅过滤器文档。)

在实际运行 Checkstyle 时,您可能希望将其限制在那个源文件中。 例如,如果使用 Ant,您可以这样做:

<taskdef resource="com/puppycrawl/tools/checkstyle/ant/checkstyle-ant-task.properties"
     classpath="tools/checkstyle-8.33-all.jar"/>

<checkstyle config="checkstyle.xml">
    <fileset dir="src/main/java" includes="**/TestType.java"/>
</checkstyle>

没有办法保护成员免受其自己的 class 的影响,但是您可以保护成员免受其子类/子类的影响。 例如:

class TestParent {
    private String value;

    public String getValue() {
        return this.value == null || this.value.isEmpty() ? "default" : this.value;
    }

    public void setValue(String newValue) {
        this.value = newValue;
    }

}

class TestType extends TestParent {
    public int getValueLength() {
        return this.getValue().length();
    }
}

这样 TestType 仍然可以使用setValue()getValue() ,但是尝试直接访问this.value将不起作用,因为valueTestParent中具有私有访问权限

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM