关于文件标记化、对象值设置和令牌位置枚举的 API 设计



在我的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);
    }      
  }
}

相关内容

  • 没有找到相关文章

最新更新