Java-在超类中注入资源,而不在基类中公开setter
也许这是一个简单的问题,但我还没有找到解决办法。我有这样的类配置:Java-在超类中注入资源,而不在基类中公开setter,java,Java,也许这是一个简单的问题,但我还没有找到解决办法。我有这样的类配置: abstract class SuperA { Resource a; Resource b; public SuperA() { } public SuperA(Resource a, Resource b) { this.a = a; this.b = b; } protected Resource getResourceA() { ret
abstract class SuperA {
Resource a;
Resource b;
public SuperA() {
}
public SuperA(Resource a, Resource b) {
this.a = a;
this.b = b;
}
protected Resource getResourceA() {
return a;
}
protected Resource getResourceB() {
return b;
}
}
class BaseA extends SuperA {
public method1() {
Resource myResource = getResourceA();
}
}
class Manager {
public Manager() {
// I want to instantiate BaseA and inject some resources, but can't do
// it through the constructor
BaseA baseA = new BaseA(/*can't place parameters*/);
// I could use Setters, but this would expose the Setters to BaseA too...
baseA.setResourceA(new Resource());
baseA.setResourceB(new Resource());
}
}
在这种情况下,我想将资源注入到超类中,而不向其基类公开任何Setter,也不继承构造函数,有什么方法可以做到这一点吗
更新-澄清
BaseA
类是API的扩展,我不希望其他用户有权修改实例化BaseA
的核心引擎注入的资源。我希望BaseA
使用资源而不是修改它们。不允许访问构造函数基类的动机不清楚,而这显然是(IMHO)最好的选择:
class BaseA extends SuperA {
public BaseA() {
super(new Resource(), new Resource()); // whatever
}
}
或者有反射:
class Manager {
public Manager() throws Exception {
BaseA baseA = new BaseA();
Field f = SuperA.class.getDeclaredField("a");
f.setAccessible(true);
f.set(baseA, new Resource()); // however you create a Resource
// similar for field "b"
}
}
一个选项是这样的setter,即“包可见”和“最终” 在方法声明中使用final关键字表示 方法不能被子类重写。从 然后使用“包私有”访问级别修饰符(后面不是确切的引用,而是解释) (未说明“公共”、“私人”或“受保护”)这意味着 类本身可以看到/使用方法,类位于同一个确切的包中 可以查看/使用该方法,但子类和世界无法查看/使用 方法 单独使用“package private”可能会解决您的问题,但我会使用“final”只是为了使所需的行为更加明显,从而有助于将来的代码工作,等等 例如:
abstract class SuperA {
// making these private also helps
// because it limits child classes to ONLY use getters
// they can't even 'fiddle with' the raw values
private Resource a;
private Resource b;
// would you want this public? perhaps also no 'access-modifier'
// the 'exact' specifics of a lot of this class would depend on your
// specific use case (But I'd think you would want this package-only too most likely)
public SuperA() {
}
// note no 'access-modifier', means package use only.
SuperA(Resource a, Resource b) {
this.a = a;
this.b = b;
}
// can also have the same with setters
// again no 'access-modifier'
final setResourceA(Resource a){ this.a = a;}
final setResourceB(Resource b){ this.b = b;}
public final Resource getResourceA() {
return a;
}
public final Resource getResourceB() {
return b;
}
}
这将允许您的库访问这些方法,但不允许子类或“world”为什么您不想使用构造函数?我可以使用构造函数,但需要从基类继承它,我希望保留基类,而不允许访问更改资源。您所说的需要继承它是什么意思?如果
BaseA
扩展了SuperA
,则它可以访问所有可见的SuperA
构造函数。此外,如果资源是私有的,并且任何setter都是私有的,则一旦构建了BaseA的对象,BaseA就不能更改资源。它们必须传递给构造函数,但是构造的对象不能改变它们。不,它不能。Manager
类试图在BaseA
中获取一个实例,但除非BaseA
覆盖它,否则它无法看到SuperA
的构造函数。这就是问题所在。为什么要投反对票呢???谢谢你的回答。是的,反思将是一个解决方案。事件,但如果它是一个高流量例程,则会带来性能损失。@Joe请参阅编辑以回答某些代码的问题。性能惩罚并不是那么高——如果它是你需要的解决方案,就用它。是的,我会考虑的。我需要验证这部分代码中的反射成本。在一个不太易转换的代码中,这不会是一个问题。谢谢。@Joe我刚刚对上面的反射基代码做了一个快速性能测试:上面的代码不到10微秒(0.01毫秒)。除非你每秒要创建数千个这样的东西,否则性能不应该是个问题。是的,它只允许核心api访问setter,而不允许子类或其他任何人。谢谢。如果管理器类在不同的包中,但在同一个jar文件中,该怎么办?我不得不将Manager
类移动到SuperA
的同一个包中,以使其正常工作。然后,如果可以,可以重构库。因为这是提供他想要的功能的正确方式。在我看来,使用反射或其他方法不移动类似乎有点短视。当然,可能有一个有效的边缘情况(特别是在遗留代码或已经大量使用包可见性的代码中,并且您需要一个完整的重构),但我仍然认为这种方法对于“一般情况”是最好的