簡體   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