我有以下类结构:
DataStore类:
PStore
:public abstract class PStore ...
CStore1
和CStore2
CStore1.getInstance(Id)
和CStore2.getInstance(Id)
工人阶级:
public abstract class PWork...
CWork1
和CWork2
现状:
类CWork1
实现了一个内部类,其中以下代码访问了Store:
protected class fListener implements ActionListener {
public void actionPerformed(ActionEvent ae) {
CStore1.getInstance(Id).someMethod();
# NOTE: someMethod() is implemented in CStore2 as well
}
}
我需要在fListener
CWork2
课程
成为优秀的小型软件开发人员,而不是简单地将fListener
从CWork1
复制/粘贴到CWork2
课程,然后将CStore1
更改为CStore2
在其代码中,我决定将其转移到父类中。
我尝试做的事情:
在名为PStore
的{{1}}中创建一个抽象方法:getStoreInstance(int Id)
在public abstract PStore getStoreInstance(int Id);
中将该方法实施为CStore1
到目前为止,这么好。它编译了所有3个商店类。
将fListener代码从public PStore getStoreInstance(int Id) { return CStore1.getInstance(Id); }
复制到PWork
类
显然,编译器抱怨它对CStore1类及其方法CWork1
现在,我决定只调用新创建的getStoreInstance()
:
旧代码:getStoreInstance()
新代码:CStore1.getInstance(Id).someMethod();
编译器投诉:“无法从PStore类型中对非静态方法getStoreInstance(Id)进行静态引用”。
Eclipse提出的唯一“修复”是将getStoreInstance()方法设为静态,但这样做也不起作用:
当我在抽象类的方法声明中添加PStore.getStoreInstance(Id).someMethod();
修饰符时:static
- 编译器抱怨“PStore类型中的抽象方法getStoreInstance只能设置可见性修饰符,一个公共的或受保护的“
当我试图让这个方法变得非抽象时:public static abstract PStore getStoreInstance(int Id);
它抱怨该方法需要一个体(非常合理)
当我试图添加一个身体时,它要求我返回PStore对象......但是!!!!我的抽象类PStore没有构造函数,所以我无法返回PStore对象!!!
我是否正确接近了问题?
如果没有,我应该如何处理?
如果我是,那么我可以解决原始投诉关于“无法对非静态方法进行静态引用”,因为抽象类没有放弃我让那个方法静止了吗?
答案 0 :(得分:1)
它看起来对我来说,你有两个同构的层次结构(如果我使用正确的术语)并且相应的类之间存在关系:
PStore PWork
/ \ / \
/ \ / \
CStore1 CStore2 CWork1 CWork2
^ ^ ^ ^
| | | |
|---------+--------------| |
| |
|---------------------|
但我不认为有一种内置的方式来表达Java中的这种关系。
不知何故,你将不得不做一些使这些关系明确的事情。即需要CWork1
中引用CStore1
的内容,CWork2
内引用CStore2
的内容,或者某种与之关联的列表或地图。
可能有一种设计模式可以解决这个问题,但我现在想不到它。所以,在我的脑海中,这里有几个可能的解决方案(两者都不使用反射):
将您在getStoreInstance
中定义的抽象PWork
方法替换为PStore
。在CWork1
中,使用调用CStore1.getInstance
的方法覆盖它,类似地在CWork2
中覆盖它。然后,常见的fListener
actionPerformed
代码将调用getStoreInstance(Id).someMethod()
,没有类名,这将适用于当前的PWork
实例。您仍然会有一些“重复”代码(因为您必须在getStoreInstance
个类中实现CWork
),但它会保持最低限度。
设置地图。这编译(Java 8),但我还没有测试过它:
class PWork {
private static Map<Class<? extends PWork>,IntFunction<PStore>> storeMap;
static {
storeMap = new HashMap<>();
storeMap.put(CWork1.class, CStore1::getInstance);
storeMap.put(CWork2.class, CStore2::getInstance);
}
protected PStore getStoreInstance(int Id) {
return storeMap.get(getClass()).apply(Id);
}
protected class fListener implements ActionListener {
public void actionPerformed(ActionEvent ae) {
int Id = ???; // I'm assuming Id is computed from ae somehow??
getStoreInstance(Id).someMethod();
}
}
}
现在getStoreInstance
在地图中查找,使用当前PWork
对象的类(CWork1
或CWork2
)作为关键字,找出getInstance
静态方法来调用。
答案 1 :(得分:1)
是的,你可以在PStore上使用静态方法,而不是重复代码。
使您的工作人员具有通用性,保留类令牌引用,并调用
public class Worker<T extends PStore> {
private final Class<T> c;
public Worker(Class<T> c) {
this.c = c;
}
public void actionPerformed(ActionEvent ae) {
PStore.getInstance(c, Id).someMethod();
}
// other methods
}
现在对于PStore中的静态方法,它不必是通用方法:worker不必知道返回的实际类型,它只是正确的类型。
public class PStore {
private static Map<Class<?>, List<PStore>> map = new HashMap<>();
protected PStore() {
List<PStore> list = map.get(getClass());
if (list == null) {
list = new ArrayList<>();
map.put(getClass(), list);
}
list.add(this);
}
public static PStore getInstance(Class<? extends PStore> c, int i) {
return map.get(c).get(i);
}
public abstract void someMethod();
}
这里的好处是N个实例的上限留给了PStore子类。还要注意列表是如何包含PStore实例的,它们实际上是子类实例,但PStore和worker都不关心(只要它实际上是返回的所需子类,它将会是这样)。
免责声明:我在手机上输入了这个内容,因此可能无法编译 - 请告诉我是否有问题,我会尝试修复它。
答案 2 :(得分:0)
编译器是正确的,因为在静态上下文中引用实例方法不起作用。在静态世界中,您正在处理类级别并处理整个类的属性。如果您尝试调用实例方法,编译器如何知道您要执行实例方法的实例?
使抽象方法不起作用,因为必须在子类中实现抽象方法。但是,静态方法不能被覆盖 - 只能隐藏。因此,如果在抽象方法上允许static
,并且您尝试执行AbstractClass.staticMethod()
,那么运行时将使用哪种实现?
您的代码有点难以理解,但这就是我的想法。基于名称,getStoreInstance(int Id)
应该是一个静态方法,因为实例获取另一个实例没有多大意义;这似乎更像是班级应该做的事情。您可能想重新考虑如何构建代码...从代码名称来看,您似乎应该使用类级别的方法来跟踪类的实例,因此可能会执行类似的操作并实现{{1}和getInstance()
作为静态方法会是一个开始吗?