簡體   English   中英

僅將getter方法共享給客戶端的最佳方法是什么?

[英]What is the best way to share only the getter methods to client?

我正在用這樣的類編寫一個API:

public class NKMPMission {
    private String name;
    private int age;
    public NKMPMission(String name, int age)
    {
         this.name  = name;
         this.age   = age;
    }
    public String getName() 
    {
       return name;
    }

    public int getAge() 
    {
       return age;
     }
   }

我的問題:

  1. 如何確保此NKMPMission類的用戶僅訪問getter?
  2. 如何為這個功能引入setter,以便我作為開發人員可以設置,但用戶無法設置?

通常的方法是不公開類,只是公開該類的接口。 一個公共界面和一個開發人員界面。

然后,您需要一個工廠來創建它們。

/**
 * Expose this interface to the public.
 */
public interface INKMPMission {

    public String getName();

    public int getAge();

}

/**
 * Only expose this interface to developers.
 */
interface IDeveloperNKMPMission {

    public void setName(String name);

    public void setAge(int age);

}

public static class NKMPMissionFactory {

    /**
     * Expose only the INKMPMission construction.
     */
    public INKMPMission make(String name, int age) {
        return new NKMPMission(name, age);
    }

    /**
     * Protected version for developers.
     */
    IDeveloperNKMPMission forDeveloper(INKMPMission it) {
        return IDeveloperNKMPMission.class.cast(it);
    }

    /**
     * Private so no-one outside the factory knows about the inner workings.
     */
    private static class NKMPMission implements INKMPMission, IDeveloperNKMPMission {

        private String name;
        private int age;

        private NKMPMission(String name, int age) {
            this.name = name;
            this.age = age;
        }

        @Override
        public String getName() {
            return name;
        }

        @Override
        public int getAge() {
            return age;
        }

        @Override
        public void setName(String name) {
            this.name = name;
        }

        @Override
        public void setAge(int age) {
            this.age = age;
        }
    }
}

對於真正的偏執狂,你甚至可以使用代理。 這將使得通過反射使用設定者變得困難(但並非不可能)。

    /**
     * Expose only the INKMPMission construction.
     */
    public INKMPMission make(String name, int age) {
        return new NKMPMissionProxy(new NKMPMission(name, age));
    }

    /**
     * Protected version for developers.
     */
    protected IDeveloperNKMPMission forDeveloper(INKMPMission it) {
        if (it instanceof NKMPMissionProxy) {
            it = ((NKMPMissionProxy) it).theMission;
        }
        return IDeveloperNKMPMission.class.cast(it);
    }

    /**
     * A proxy for the truly paranoid - makes using reflection more difficult (but not impossible)
     */
    private static class NKMPMissionProxy implements INKMPMission {
        private final NKMPMission theMission;

        private NKMPMissionProxy(NKMPMission theMission) {
            this.theMission = theMission;
        }

        @Override
        public String getName() {
            return theMission.getName();
        }

        @Override
        public int getAge() {
            return theMission.getAge();
        }


    }

1)我如何確保此NKMPMIssion類的用戶只能訪問getter。

你不能。

2)我如何為此功能引入setter,以便作為開發人員我應該能夠設置,但用戶不應該設置。

這聽起來像是在編寫API。 如果從該API的公共方法返回NKMPMIssion實例,則可以調用setter。 即使您將它們標記為privateprotected ,它們仍然可以通過反射進行調用。 也就是說,通常讓他們不public就足夠了。 它至少會說:“如果你打電話給這些,你就處於不受支持的領域。”

如果你想讓它變得更難,你可以返回一個圍繞NKMPMIssion實例包裝外觀的實例。 但這只會讓它變得更難,而不是不可能,因為外觀實例必須引用NKMPMIssion實例,即可以通過反射訪問它(即使它是private )。

最簡單的方法是使API僅使用接口,並使該類成為實現細節。

public interface INKMPMission {        
    String getName();
    int getAge();
 }

public class SomeService{
    private class MyNKMPMission implements INKMPMission {
        //put getters and setters here
    }
    public List<INKMPMission> getMissions(){
        //put some MyNKMPMissions in a list
    }
}

由於MyNKMPMission是私有的,因此消費者將無法進行向下轉換並訪問設置者。

可以 (以某種方式),但你不應該這樣做:

  • 在每個setter構造一個新的Exception
  • 檢查生成的Stacktrace
  • 如果調用者類不在您的包中(或硬編碼某些直接類名/方法名),則拋出IllegalAccessError

這種方式既不漂亮也不快,因為您必須檢查每次訪問setter。

另一種方法是使用@CallerSensitive Annotation,雖然它是propritary API,因此不適用於所有平台/ jre實現: https ://stackoverflow.com/a/22627383/1164913

干凈,在大多數情況下是足夠的方式將使用一個接口,它只向客戶端提供getter,並將其返回給客戶端。

您似乎正在嘗試編寫API。 假設用戶意味着使用您的API的開發人員。

在這種情況下,將setter設置為protected並構建一些有意義的包結構,這樣只有child和package成員才能看到它。

如果你想保護它甚至是孩子的,除了把它變成私人之外別無他法。

回答問題:

Q1。 你不能像TJ克勞德在他的回答中所說的那樣。

Q2。 我建議您按照以下順序嘗試以下事項,從最簡單到最難,並采取您認為最適合努力回報的選項:

  1. 看看: Java訪問修飾符
  2. 創建一個接口,並使用公共方法將該接口公開給“NKMPMission”類的“最終”用戶,如Esben Skov Pedersen回答中所述
  3. 最后,您可以使用OldCurmudgeon中提到的代理方法回答

我會怎么做:

如果您的類集將在內部使用,那么我將選項1與良好的javadoc和項目標准相結合,它應該就足夠了。

如果您要創建公共API,我會選擇2。

恕我直言,選項3在這種情況下增加了太多不必要的復雜性,並且很少受益,因為無論如何都可以訪問每個類方法或屬性拋出反射(正如許多人所提到的)。 我想每個人都知道,對API的隱藏方法的訪問拋出反射是hacky,危險並且不方便項目的管理,因為API提供者有權更改隱藏的方法實現,而無需進一步通知最終用戶。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM