我正在尝试在 Java 中实现一个接口(interface),以便为一个应用程序使用不同类型的数据库。 我的想法是创建一个具有公共(public)接口(interface)和两个静态变量的抽象类,然后它们被子类覆盖。然后,我想添加一个 Class[] 列表,其中包含抽象类中所有可用子类的类,以及几个允许确定要使用的正确类的函数。
目标是首先获取所有可用数据库类型的列表,然后让用户选择一个。之后另一个函数应该将名称(可以本地化)翻译为 IDENTIFIER
这是在子类中指定的。最后,第三个函数允许通过给出这样的 IDENTIFIER
来实例化对象。 .
我的抽象类看起来像这样:
public abstract class DataBase {
public static final IDENTIFIER = "";
public static final NAME = "";
private static final Class[] dbTypes = new Class[]{PostgreSQL.class, MySQL.class};
public static String[] getNameList() {
String[] names = new String[dbTypes.length];
for(int i = 0; i < dbTypes.length; i++){
names[i] = dbTypes[i].NAME; //Cannot access the static variable this way.
}
return names;
}
public static String getIdentifierForName(String name) {
for(int i = 0; i < dbTypes.length; i++){
if(name.equals(dbTypes[i].NAME){
return dbTypes[i].IDENTIFIER;
}
}
return "";
}
public static DataBase getInstanceOf(String identifier) {
for(int i = 0; i < dbTypes.length; i++){
if(identifier.equals(dbTypes[i].IDENTIFIER) {
return dbTypes[i].newInstance();
}
}
return null;
}
}
Child 类看起来像这样:
public class MySQL extends DataBase {
public static final IDENTIFIER = "ab.cde.MySQL";
public static final NAME = "MySQL";
...
}
public class PostgreSQL extends DataBase{
public static final IDENTIFIER = "ab.cde.PostgreSQL";
public static final NAME = "PostgreSQL";
...
}
我现在的问题是,我无法从 Class 对象访问静态变量。显然 dbTypes 列表不包含任何类型化类。我尝试将数组的类型更改为 Class<? extends DataBase>
,但我收到错误 Cannot create a generic array of Class<? extends DataBase>
我还尝试使用 isAssignableFrom()
检查类(class)然后转换类,但我仍然无法访问静态变量。
目前我有两个有效的解决方案:
将所有现有子类硬编码到每个函数中
if(PostgreSQL.NAME.equals(name)){...}
ETC。 但是,如果我添加新的子类,我只想在实现中的某一时刻添加它们。我可以使用包含每个类实例的 DataBase[] 数组,而不是使用 Class[] 数组。但是,我认为实例化每个可用的 DataBase 子类是一种不好的做法,即使我最终只需要一个。
由于我以前从未做过这样的事情,所以我可能完全错误地处理了这个问题。也许我错过了通常完成此类事情的正确方法?
感谢您的帮助。
最佳答案
Java 中没有“抽象属性”。您必须在 DataBase
类中创建两个抽象方法,如下所示:
public abstract class DataBase {
// No "abstract propeties"
public abstract String getDBName();
public abstract String getDBIdentifier();
// etc etc...
}
然后,在每个子类中:
public class MySQL extends DataBase {
public static final IDENTIFIER = "ab.cde.MySQL";
public static final NAME = "MySQL";
@Override
public String getDBName() {
return NAME;
}
@Override
public String getDBIdentifier() {
return IDENTIFIER;
}
// etc etc...
}
使用这些类时,您只需转换为DataBase
(不是MySQL
或PostgreSQL
)并调用两个抽象方法。
因此,为了解决您的“选择数据库类”问题,我将创建一个包含数据库名称和相应类的配置文件,并通过反射实例化它(newInstance()
)根据需要。
作为替代方案,您可以使用反射来访问静态变量,如 Nikita 建议的答案,或者您可以使用类的名称作为它支持的数据库的标识符,如下所示(未测试):
public abstract class DataBase {
private static final Class[] dbTypes = new Class[]{PostgreSQL.class, MySQL.class};
public static Class getDBClass(String type) {
for (Class c : dbTypes) {
if (c.getSimpleName().toLowerCase().equals(type.toLowerCase())) {
return c;
}
}
return null;
}
public static Set<String> getSupportedDB() { // <-- you populate a dropdown menu with this
Set<String> supported = new HashSet<String>();
for (Class c : dbTypes) {
supported.add(c.getSimpleName());
}
return supported;
}
// etc etc...
}
但是,我不喜欢这个解决方案,也不会使用它。
关于java - 通过访问 Class 对象中的静态变量来确定选择哪个子类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14954017/