在我的Android应用程序中,我需要从一组最初(现在仍然(使用Windows应用程序部署的.ini文件中读取大量数据。该应用程序与特定的硬件有关,.ini文件的基本目的是描述有关硬件设备的编程常量,实时数据和UI元素。
为了进入我需要帮助的特定 Java 设计问题,下面是一个示例,说明如何构建 .ini 文件中的典型数据行。通常我们有一个参数名称,后跟各种字符串或数字数据列:
example = example, "example", "C", 0, 255, -1, -1, 256, 256
然后,我解析和标记化的每一行数据在应用程序中表示为一个对象。为了从每行.ini文件数据中执行每个对象的创建,我目前正在使用构建器/流利接口。因此,上面的行将导致创建如下对象:
someObject.setName( t.s(2) ).setUnits( t.s(3) ).setLowerUpper( t.f(4), t.f(5) ) ...
t
是我的 tokenizer 类实例,用于解析 .ini 文件,其方法 s(int)
和 f(int)
是获取给定列号的整数或浮点数的 getter。
这有点混乱,因为我的基本.ini文件处理类基于从分词器返回的数据执行对象创建,必须在行列的所有位置都包含幻数。我还必须注意适当地使用 s()
或 f()
(尽管如果我使用错误的编译器,编译器当然会根据对象设置器所需的类型报告错误(。
我真正想做的是有另一个类,我可以称之为IniFileDefinitions。理想情况下,该类将包含行号及其关联类型的枚举定义。因此,使用此类,上面的对象创建可能类似于以下内容(显然是伪代码(:
someObject.setName( t.get(INI_NAME) ).setUnits( t.get(INI_UNITS) ).setLowerUpper( t.get(INI_LOWER), t.get(INI_UPPER) );
我有点纠结的地方是如何定义一个可以传递给我的分词器的枚举值,并让分词器不仅使用该枚举来确定列号,而且还根据该枚举改变返回的类型(整数、字符串、浮点数等(。
我意识到 Java 枚举非常强大,我可以为每个枚举有两个字段,其中第一个字段给出行号,第二个字段描述类型,例如:
public enum someIniEnumDefs{
INI_NAME( 2, INI_TYPE_STRING )
...
我突然想到,完成这项工作的一种方法是在我的分词器中使用一个 getter 方法,该方法可以根据枚举所说的类型来改变它返回的类型,但显然这在 Java 中是不可能的。据我所知,我必须返回一个包含所有类型(字符串、整数、...(之一的自定义对象,或者只是简单地返回 Object(呃(。我不是特别喜欢这两种解决方案。
我的一个想法是,分词器可以有多个(重载(值 get(( 方法,每个方法返回不同的基元类型。将调用哪个特定的 get(( 方法可能以某种方式取决于枚举定义中的"类型"字段。我认为我没有任何办法可以做到这一点。我想到的唯一方法是将我的枚举分成几个代表不同类型的组,然后我的分词器 get 方法将像这样重载:
int get(SomeIniEnumDefs_Ints){ ... return someInt }
String get(SomeIniEnumDefs_Strings){ ... return someString }
...
鉴于我缺乏Java枚举的经验(我知道它比我习惯的普通C要强大得多!我知道一定有一个巧妙的方法可以做到这一点。任何人都可以提供任何进一步的指导吗?
谢谢
崔佛
你尝试做的事情是用Java枚举无法实现的。但是,可以通过另一种方式轻松实现:
public class IniParam<T> {
public static final IniParam<String> NAME = new IniParam<String>(2);
public static final IniParam<String> UNITS = new IniParam<String>(3);
public static final IniParam<Integer> LOWER = new IniParam<Integer>(4);
public static final IniParam<Integer> UPPER = new IniParam<Integer>(5);
private final int position;
private IniParam(int position) {
this.position = position;
}
public int getPosition() {
return position;
}
}
然后,分词器可能如下所示:
public class Tokenizer {
public String get(IniParam<String> iniParam) {
int position = iniParam.getPosition();
//...
return "some string from .ini";
}
public int get(IniParam<Integer> iniParam) {
// ...
// return some integer from .ini
}
}
使用示例:
Tokenizer t = new Tokenizer();
String name = t.get(IniParam.NAME);
int lower = t.get(IniParam.LOWER);
someObject.setName( t.get(IniParam.NAME) ).setUnits( t.get(IniParam.UNITS) ).setLowerUpper( t.get(IniParam.LOWER), t.get(IniParam.UPPER) );
更新
不幸的是Tokenizer
我上面提供的类将无法使用 JDK 7/Eclipse 3.6+ 编译器进行编译(我现在无法自己检查,但以下 Oracle 和 Eclipse 错误的修复假设get(...)
方法中的编译错误(。如果您遇到此问题,这里是解决方法:
public class IniParam<T> {
public static final IniParam<String> NAME = new IniParam<String>(2, String.class);
public static final IniParam<String> UNITS = new IniParam<String>(3, String.class);
public static final IniParam<Integer> LOWER = new IniParam<Integer>(4, Integer.class);
public static final IniParam<Integer> UPPER = new IniParam<Integer>(5, Integer.class);
private final int position;
private final Class<? extends T> type;
private IniParam(int position, Class<? extends T> type) {
this.position = position;
this.type = type;
}
public int getPosition() {
return position;
}
public Class<? extends T> getType() {
return type;
}
}
public class Tokenizer {
public <T> T get(IniParam<T> iniParam) {
int position = iniParam.getPosition();
Class<? extends T> type = iniParam.getType();
if (type == String.class) {
//...
return type.cast("some string from .ini");
} else if (type == Integer.class) {
//...
// Integer result = ...;
return type.cast(result);
} else {
throw new IllegalArgumentException("Unexpected IniParam type: " + type);
}
}
}