将switch语句替换为映射(针对不同的数据类型)

时间:2015-06-23 19:56:20

标签: java generics switch-statement refactoring

我正在尝试用地图替换以下switch语句。

public ObjGeometry geometry(final Iterable<String> lines) throws IllegalArgumentException {
    final List<Vector3f> vertices = Lists.newArrayList();
    final List<Vector2f> textures = Lists.newArrayList();
    final List<Vector3f> normals = Lists.newArrayList();
    final List<Face> faces = Lists.newArrayList();

    for (final String line : lines) {
      final List<String> lineElements = Arrays.asList(line.split(" "));
      final String token = lineElements.get(0);

      switch (token) {
        case VERTEX:
          final Vector3f vertex = createVertex(lineElements);
          vertices.add(vertex);
          break;
        case TEXTURE:
          final Vector2f texture = createTexture(lineElements);
          textures.add(texture);
          break;
        case NORMAL:
          final Vector3f normal = createNormal(lineElements);
          normals.add(normal);
          break;
        case FACES:
          final Face face = createFace(lineElements);
          faces.add(face);
          break;
      }
    }
    return ObjGeometry.from(vertices, textures, normals, faces);
  }

方法#createVertex#createTexture#createNormal#createFace将字符串转换为特殊数据类型(Vector2f,Vector3f或Face)

我想要做的是......构建一个Map Map<TOKEN, Parser>,这样我就可以遍历那个map并调用正确的解析器来获取一个特殊的令牌(顺便说一下.TOKEN是一个像“v”这样的字符串, “vt”,“vn”或“f”)。

我拥有的是:

  • 使用方法ExtractVector3f的抽象类#vectorFrom(List<String>) - 可以将List<String>转换为Vector3f
  • 使用方法ExtractVector2f的抽象类#vectorFrom(List<String>) - 可以将List<String>转换为Vector2f
  • 使用方法ExtractFace的抽象类#faceFrom(List<String>) - 可以将List<String>转换为Face
  • 接口LineParser

    public interface LineParser<T> {
      T apply(final List<String> lineElements);
    }
    
  • 一个解析顶点的类

    public class ParseVertex extends ExtractVector3f implements LineParser<Vector3f> {
      @Override
      public Vector3f apply(final List<String> lineElements) {
        return vectorFrom(lineElements);
      }
    }
    
  • 解析普通

    的类
    public class ParseNormal extends ExtractVector3f implements LineParser<Vector3f> {
      @Override
      public Vector3f apply(final List<String> lineElements) {
        return vectorFrom(lineElements);
      }
    }
    
  • 用于解析纹理的类

    public class ParseTexture extends ExtractVector2f implements LineParser<Vector2f> {
      @Override
      public Vector2f apply(final List<String> lineElements) {
        return vectorFrom(lineElements);
      }
    }
    
  • 和一个解析面部的类

    public class ParseFace extends ExtractFaces implements LineParser<Face> {
      @Override
      public Face apply(final List<String> lineElements) {
        return faceFrom(lineElements);
      }
    }
    

下一步是构建地图......类似于

    Map<String, LineParser> parsers = Maps.newHashMap();
        parsers.put("v", new ParseVertex());
        parsers.put("vt", new ParseTexture());
        parsers.put("vn", new ParseNormal());
        parsers.put("f", new ParseFace());

但是现在我遇到了麻烦。此映射中的LineParser是原始类型,应避免使用原始类型。

我的问题是: 如何使用POJO构建一个映射 - 它在通过接口定义的方法上返回不同的数据类型?

1 个答案:

答案 0 :(得分:2)

实际上,我不会这样做。即使地图是个好主意,这样做也会丢失您构建的对象的确切类型。那之后你会怎么处理他们?你怎么知道添加它们的集合?除非解析器可以访问所有集合以选择正确的集合,否则您无法做到。这表明解析器应该知道你的主类或这个类的方法。

我会使用lambdas:

Consumer<List<String>> handleTexture = args -> textures.add(parseTexture(args))
Consumer<List<String>> handleVertice = args -> vertices.add(parseVertice(args))
...
Map<String, Consumer<List<String>> handlers = new HashMap<>();
handlers.put("vf", handleTexture);
handlers.put("v", handleVertice);
...

for (final String line : lines) {
      final List<String> lineElements = Arrays.asList(line.split(" "));
      final String token = lineElements.get(0);
      handlers.get(token).accept(lineElements.sublist(1, lineElements.size()));)
}

如果你想用Java 7做它,它在语法上不太好,但原理是一样的。使用方法Consumer创建accept之类的界面(如果您希望让课程更具体,请更改所有名称,例如Parserparse,只保留方法的相同签名):

public class Consumer<T> {
     public void accept(T t);
}

然后,在你的代码中

Consumer<List<String>> handleTexture = new Consumer<List<String>>() { 
    @Override
    public void accept(List<String> args) {
        textures.add(parseTexture(args));
    }
}

剩下的就是一样!