我正在编写一个类似这样的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;
}
}
我的问题:
NKMPMission
类的用户仅访问getter?答案 0 :(得分:21)
通常的做法是不公开类,只是将接口暴露给该类。一个公共界面和一个开发者界面。
然后你需要一个工厂来创建它们。
/**
* 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;
}
}
}
对于真正的偏执狂,你甚至可以使用代理。这将使通过反射使用setter变得困难(但并非不可能)。
/**
* 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 :(得分:6)
1)如何确保此NKMPMIssion类的用户只能访问getter。
你不能。
2)我如何为此功能引入setter,以便作为开发人员我应该能够设置,但用户不应该设置。
听起来你在编写API。如果从该API的公共方法返回NKMPMIssion
实例,则可以调用setter。即使您将它们标记为private
或protected
,它们仍然可以通过反射进行调用。也就是说,通常将它们设为非public
就足够了。它至少会说“如果你打电话给这些,你就处于不受支持的领域。”
如果你想让它变得更难,你可以在NKMPMIssion
实例周围返回一个包装 facade 的实例。但这只会让它变得更难,而不是不可能,因为Facade实例必须引用NKMPMIssion
实例,这可以通过反射访问(即使它是private
)。
答案 2 :(得分:4)
最简单的方法是让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是私有的,因此消费者永远无法进行向下转换并访问设置者。
答案 3 :(得分:3)
你可以(以某种方式),但你应该不这样做:
这种方式既不漂亮也不快,因为你必须检查对setter的每次访问。
另一种方法是使用@CallerSensitive
Annotation,虽然它是propritary API,因此不适用于所有平台/ jre实现:https://stackoverflow.com/a/22627383/1164913
干净,在大多数情况下是足够的方式是使用一个接口,它只向客户端提供getter,并将其返回给客户端。
答案 4 :(得分:2)
您似乎在尝试编写API。假设用户是指使用您的API的开发人员。
在这种情况下,将setter设为protected
并构建一些有意义的包结构,这样只有子代和包成员才能看到。
如果你想保护孩子的这一点,除了把它变成私人之外别无选择。
答案 5 :(得分:2)
回答问题:
Q1。你不能像T.J. Crowder在他的回答中所说的那样。
Q2。我建议您按照以下顺序尝试以下事项,从最简单到最难,并采取您认为最适合努力回报的选项:
我会做什么:
如果您的内部课程将在内部使用,那么我会将选项1与良好的javadoc和项目标准相结合,这应该足够了。
如果您要创建公共API,我会选择2.
恕我直言,选项3在这种情况下增加了太多不必要的复杂性,并且很少受益,因为无论如何都可以访问每个类方法或属性抛出反射(正如许多人所提到的)。我想每个人都知道这样一个事实,即API隐藏方法的访问权限反映是hacky,危险且不便于项目的管理,因为API提供商有权在没有进一步通知的情况下更改隐藏的方法实现给最终用户。