仅向客户端共享 getter 方法的最佳方法是什么



我正在用这样的类编写一个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实例,则可以调用资源库。即使你将它们标记为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是私有的,因此消费者将永远无法进行向下投射并访问设置器。

你可以

(以某种方式(,但你不应该那样做:

  • 在每个资源库中构造一个新的异常
  • 检查生成的堆栈跟踪
  • 如果调用者类不在你的包中(或硬编码一些直接类名/方法名(,抛出一个非法访问错误

这种方式既不漂亮,也不快,因为您必须检查对二传手的每一次访问。

另一种方法是使用@CallerSensitive注释,尽管它是专有的API,因此并非在所有plattforms/jre实现上都可用:https://stackoverflow.com/a/22627383/1164913

干净且在大多数情况下足够的方法是使用仅向客户端提供 getter 的接口,并将其返回给客户端。

您似乎正在尝试编写 API。假设用户是指使用您的 API 的开发人员。

在这种情况下,将 setter 设为protected并构建一些有意义的包结构,以便只有子成员和包成员才能看到。

如果你想保护它,即使是孩子的,除了把它保密之外别无

他法。

回答问题:

问题 1.你不能像T.J.克劳德在他的回答中所说的那样。

问题 2.我建议您按照以下顺序从最简单到最难尝试以下方法,并采取您认为最合适的努力回报选项:

  1. 看看:Java 访问修饰符。
  2. 创建一个接口,
  3. 并将该接口与公共方法公开给"NKMPMission"类的"最终"用户,如 Esben Skov Pedersen 答案中所述
  4. 最后你可以做OldCurmudgeon答案中提到的代理方法

我会做什么:

如果你的类集要在内部使用,那么我会选择选项 1 与良好的 javadoc 和项目标准相结合,这应该就足够了。

如果您正在创建公共 API,我会选择选项 2。

恕我直言,在这种情况下,选项 3 增加了不必要的复杂性,并且几乎没有什么好处,因为无论如何都可以访问每个类方法或属性抛出反射(正如许多人提到的(。我想每个人都知道这样一个事实,即对 API 隐藏方法的访问抛出反射是黑客的、危险的,并且不方便项目的管理,因为 API 提供者有权更改隐藏方法的实现,而无需进一步通知最终用户。

相关内容

最新更新