如何简化庞大的 switch-case 表达式?

huangapple go评论88阅读模式
英文:

How to simplify huge switch-case expression?

问题

以下是翻译好的内容:

我在下面的代码中遇到了一些问题。
我有一个简单的接口,如下所示:

public interface Game {
    int start();
}

许多实现了这个接口的类,例如:

public class FirstGame implements Game {
    public static final int ID = 1;
    
    @Override
    int start() {
        // 做一些事情并返回结果
    }
}

还有一个GameManager类,有一个如下所示的方法:

public Game getGameById(int id) {
    switch(id) {
        case FirstGame.ID:
            return new FirstGame();
        case SecondGame.ID:
            return new SecondGame();
        // ..... 和许多其他情况.....
    }
    return null;
}

我试图使用反射来简化这个switch-case结构,代码如下:
注解:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface GameId {

long value() default 0;
}

FirstGame类:

@GameId(value = 1)
public class FirstGame implements Game {
    public static final int ID = 1;
    
    @Override
    int start() {
        // 做一些事情并返回结果
    }
}

GameManager的方法如下:

public Game getGameById(int id) {
    Game game = null;
    try {
        Reflections reflections = new Reflections();
        for (Class<?> clazz : reflections.getTypesAnnotatedWith(GameId.class)) {
            if (clazz.getAnnotation(GameId.class).value() == id) {
                Constructor constructor = clazz.getConstructor();
                game = (Game) constructor.newInstance();
                break;
            }
        }
    } catch (Exception ex) { ex.printStackTrace(); }
    return game;
}

但是它运行得太慢了。
那么,有没有其他方法来简化switch-case表达式呢?
谢谢,抱歉英语不太好。

英文:

I have got some troubles with next code.
I have simple interface like:

public interface Game {
    int start();
}

Many classes that implements this interface like:

public class FirstGame implements Game {
    public static final int ID = 1;
    
    @Override
    int start() {
        // Do something and return result
    }
}

And GameManager class that has one method like this:

public Game getGameById(int id) {
    switch(id) {
        case FirstGame.ID:
            return new FirstGame();
        case SecondGame.ID:
            return new SecondGame();
        // ..... and many other cases....
    }
    return null;
}

I was trying to simplify this switch-case construction using reflection like this:
Annotation:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface GameId {

long value() default 0;
}

FirstGame class:

@GameId(value = 1)
public class FirstGame implements Game {
    public static final int ID = 1;
    
    @Override
    int start() {
        // Do something and return result
    }
}

And GameManager method like this:

public Game getGameById(int id) {
    Game game = null;
    try {
        Reflections reflections = new Reflections();
        for (Class&lt;?&gt; clazz : reflections.getTypesAnnotatedWith(GameId.class)) {
            if (clazz.getAnnotation(GameId.class).value() == id) {
                Constructor constructor = clazz.getConstructor();
                game = (Game) constructor.newInstance();
                break;
            }
        }
    } catch (Exception ex) { ex.printStackTrace();}
    return game;
}

But it works too slow.
So, how to simplify switch-case expression in some other way?
Thanks and sorry for broken English.

答案1

得分: 1

这个怎么样?

static final List<Supplier<Game>> GAMES = List.of(
    FirstGame::new,
    SecondGame::new
    // ...
);

public Game getGameById(int id) {
    return GAMES.get(id).get();
}

或者

static final Map<Integer, Supplier<Game>> GAMES = Map.of(
    1, FirstGame::new,
    2, SecondGame::new
);

public Game getGameById(int id) {
    return GAMES.get(id).get();
}
英文:

How about this?

static final List&lt;Supplier&lt;Game&gt;&gt; GAMES = List.of(
    FirstGame::new,
    SecondGame::new
    // ...
);

public Game getGameById(int id) {
    return GAMES.get(id).get();
}

Or

static final Map&lt;Integer, Supplier&lt;Game&gt;&gt; GAMES = Map.of(
    1, FirstGame::new,
    2, SecondGame::new
);

public Game getGameById(int id) {
    return GAMES.get(id).get();
}

答案2

得分: 1

感谢Holger提供的答案。
通过反射的方法已经接近成功。只需在使用ID作为键时,将所有构造函数添加到HashMap中。所以现在我的GameManager代码如下:

Map<Integer, Constructor> constructorMap = new HashMap<>();

private void fillConstructorMap() {
    try {
        ConfigurationBuilder configurationBuilder = new ConfigurationBuilder();
        configurationBuilder.addUrls(ClasspathHelper.forPackage("com.my.package.name"));
        Reflections reflections = new Reflections(configurationBuilder);
        for (Class<?> clazz : reflections.getTypesAnnotatedWith(GameId.class)) {
            Integer id = clazz.getAnnotation(GameId.class).value();
            Constructor constructor = clazz.getConstructor();
            constructorMap.put(id, constructor);
        }
    } catch (NoSuchMethodException ex) {
        ex.printStackTrace();
    }
}

public Game getGameById(int id) {
    Game game = null;
    try {
        game = (Game) constructorMap.get(id).newInstance();
    } catch (Exception ex) {ex.printStackTrace();}
    return game;
}

这个方法的速度与使用switch-case表达式的方法一样快。

英文:

Thanks to Holger's for his answer.
My method with reflection was so close to success. It just needs to add all constructors to HashMap once where ID is used as key. So now my code of GameManager looks like:

Map&lt;Integer, Constructor&gt; constructorMap = new HashMap&lt;&gt;();

private void fillConstructorMap() {
    try {
        ConfigurationBuilder configurationBuilder = new ConfigurationBuilder();
        configurationBuilder.addUrls(ClasspathHelper.forPackage(&quot;com.my.package.name&quot;));
        Reflections reflections = new Reflections(configurationBuilder);
        for (Class&lt;?&gt; clazz : reflections.getTypesAnnotatedWith(GameId.class)) {
            Integer id = clazz.getAnnotation(GameId.class).value();
            Constructor constructor = clazz.getConstructor();
            constructorMap.put(id, constructor);
        }
    } catch (NoSuchMethodException ex) {
        ex.printStackTrace();
    }
}

public Game getGameById(int id) {
    Game game = null;
    try {
        game = (Game) constructorMap.get(id).newInstance();
    } catch (Exception ex) {ex.printStackTrace();}
    return game;
}

This method works so fast as method with switch-case expression.

huangapple
  • 本文由 发表于 2020年8月27日 20:22:36
  • 转载请务必保留本文链接:https://go.coder-hub.com/63615912.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定