Java中Switch Case的替代方案

有没有其他方法可以在Java中实现一个switch case,而不是看起来不好看的else。 根据选择相应的方法,必须执行一组值组合。

据推测,你正在努力解决案件不变的要求。 通常这是一种代码味道,但有些事情你可以做。 您可能想要提出并链接到另一个问题,详细说明您尝试切换的原因。

Map map = new HasMap(); // ... insert stuff into map // eg: map.add("something", new MyObject()); String key = "something"; if (map.contains(key)) { Object o = map.get(key); } 

在上面的示例中,您可能希望映射到“处理程序”,例如

 interface Handler { public void doSomething(); } 

然后使这一切变成查找。

 if (map.contains(key)) { map.get(key).doSomething(); } 

再次,这有点气味,所以请发一个说明推理的问题。

如果您的代码周围有大量的开关/案例陈述,那么它们会让您发疯。

您可以选择重构: 使用多态替换条件。

假设您有一个用于将信息保存到不同设备的软件:定义了4个持久性操作: 获取,保存,删除,更新 ,这可以通过N个持久性机制实现(平面文件,网络,RDBMS, XML等)。

您的代码必须全部支持它们,所以在4个不同的地方你有这个:

之前

 class YourProblematicClass { .... public void fetchData( Object criteria ) { switch ( this.persitanceType ) { case FilePersistance: // open file // read it // find the criteria // build the data // close it. break; case NetWorkPersistance: // Connect to the server // Authenticate // retrieve the data // build the data // close connection break(); case DataBasePersistace: // Get a jdbc connection // create the query // execute the query // fetch and build data // close connection break; } return data; } 

保存/删除/更新相同

  public void saveData( Object data) { switch ( this.persitanceType ) { case FilePersistance: // open file, go to EOF, write etc. break; case NetWorkPersistance: // Connect to the server // Authenticate // etc break(); case DataBasePersistace: // Get a jdbc connection, query, execute... break; } } 

等等….

  public void deleteData( Object data) { switch ( this.persitanceType ) { case FilePersistance: break; case NetWorkPersistance: break(); case DataBasePersistace: break; } } public void updateData( Object data) { switch ( this.persitanceType ) { case FilePersistance: break; case NetWorkPersistance: break(); case DataBasePersistace: break; } } 

使用switch / case语句会出现问题:

  • 每次要添加新类型时,都必须在每个部分中插入新的开关/案例。

  • 很多时候,某些类型是相似的,他们不需要不同的开关/案例(你可以级联它们)

  • 他们是其他一些,有时他们略有不同
  • 您甚至可能需要在运行时加载不同的类型(如插件)

因此,这里的重构将是添加接口或抽象类型,并使不同的类型实现该接口并将责任委托给该对象。

所以你会有这样的事情:

  public interface PersistenceManager { public void fetchData( Object criteria ); public void saveData( Object toSave ); public void deleteData( Object toDelete ); public void updateData( Object toUpdate ); } 

和不同的实现

  public class FilePersistence implements PersistanceManager { public void fetchData( Object criteria ) { // open file // read it // find the criteria // build the data // close it. } public void saveData( Object toSave ) { // open file, go to EOF etc. } public void deleteData( Object toDelete ){ .... } public void updateData( Object toUpdate ){ .... } } 

其他类型将根据其逻辑实现。 网络将处理套接字和流,DB将处理JDBC,ResultSets等XML与节点等.etc。

  public class NetworkPersistence implements PersistanceManager { public void fetchData( Object criteria ) { // Socket stuff } public void saveData( Object toSave ) { // Socket stuff } public void deleteData( Object toDelete ){ // Socket stuff } public void updateData( Object toUpdate ){ // Socket stuff } } public class DataBasePersistence implements PersistanceManager { public void fetchData( Object criteria ) { // JDBC stuff } public void saveData( Object toSave ) { // JDBC stuff } public void deleteData( Object toDelete ){ // JDBC stuff } public void updateData( Object toUpdate ){ // JDBC stuff } } 

最后,您只需委托调用。

后来:

 public YouProblematicClass { // not longer that problematic PersistamceManager persistance = // initialize with the right one. public void fetchData( Object criteria ) { // remove the switch and replace it with: this.persistance.fetchData( criteria ); } public void saveData( Object toSave ) { // switch removed this.persistance.saveData( toSave ); } public void deleteData( Object toDelete ){ this.persistance.deleteData( toDelete ); } public void updateData( Object toUpdate ){ this.persistance.updateData( toUpdate ); } } 

因此,您只需根据类型只为一次创建持久性管理器的正确实例。 然后通过多态来解决所有调用。 这是面向对象技术的关键特性之一。

如果您决定需要另一个持久性管理器,则只需创建新实现并分配给该类。

  public WavePersistance implements PersistanceManager { public void fetchData( Object criteria ) { // .... } public void saveData( Object toSave ) { // .... } public void deleteData( Object toDelete ){ // .... } public void updateData( Object toUpdate ){ // .... } } 

重构代码以使用多态可以摆脱对switch语句的需要。 但是,切换有一些合法用途,因此取决于您的情况。

一个丑陋的if,else if,else系列if,else if,else

或者可以想象一种动态切换案例:

 public interface Task { public void doSomething(T context); } public Class SwitchCase { Map> tasks; Task defaultTask; public void choose(int choice, T context) { Task t= this.tasks.get(choice); if(t!=null) { t.doSomething(context); return;} if(defaultTask!=null) { defaultTask.doSomething(context);} } } 

我猜“清洁代码”根据switch / case与if / else有一个很好的章节。

此外:我认为通过使用switch case,polymorphism甚至是一个好的’if / else来决定是否可以减少“噪音”并使代码更清晰是有意义的。 我想,案件的数量在这里起着重要作用。

我发布了一个典型案例,我如何用枚举替换switch case。

在重构之前我有枚举PatternTypes

 public enum PatternTypes { ALPHA_CHAR, ALPHANUMERIC_CHAR, ADDITIONAL_CHAR, UNICODE_BMP_CHARS } 

和function:

 private static final String ALPHA_CHAR = "[a-zA-Z]+"; private static final String ALPHANUMERIC_CHAR = "[a-zA-Z0-9\\_]+"; private static final String ADDITIONAL_CHAR = "[a-zA-Z0-9\\_\\-\\,\\.\\s\\!\\#\\$\\&\\(\\)\\*\\+\\;\\:\\=\\?\\@\\|\\[\\]\\{\\}\\~]+"; private static final String UNICODE_BMP_CHARS = "[a-zA-Z0-9\\_\\-\\,\\.\\s\\!\\#\\$\\&\\(\\)\\*\\+\\;\\:\\=\\?\\@\\|\\[\\]\\{\\}\\~\u00A0-\uD7FF\uF900-\uFFFD]+"; /* * Match given classAbbr with given RegEx pattern */ private void checkInvalidClassAbbr(String classAbbr, PatternTypes classAbbrPattern) { switch (classAbbrPattern) { case ALPHA_CHAR: checkUnmatched(classAbbr, ALPHA_CHAR, CLASS_ABBR_VAR_NAME); break; case ALPHANUMERIC_CHAR: checkUnmatched(classAbbr, ALPHANUMERIC_CHAR, CLASS_ABBR_VAR_NAME); break; case ADDITIONAL_CHAR: throw new MalFormedDNException("Not support Pattern Type:" + classAbbrPattern); case UNICODE_BMP_CHARS: throw new MalFormedDNException("Not support Pattern Type:" + classAbbrPattern); } } 

将重构PatternTypes修改为:

 public enum PatternTypes { /** * RegEx patterns divided by restriction level */ ALPHA_CHAR("[a-zA-Z]+"), ALPHANUMERIC_CHAR("[a-zA-Z0-9\\_]+"), ADDITIONAL_CHAR("[a-zA-Z0-9\\_\\-\\,\\.\\s\\!\\#\\$\\&\\(\\)\\*\\+\\;\\:\\=\\?\\@\\|\\[\\]\\{\\}\\~]+"), UNICODE_BMP_CHARS("[a-zA-Z0-9\\_\\-\\,\\.\\s\\!\\#\\$\\&\\(\\)\\*\\+\\;\\:\\=\\?\\@\\|\\[\\]\\{\\}\\~\u00A0-\uD7FF\uF900-\uFFFD]+"); public String getPatternContent() { return patternContent; } private String patternContent; PatternTypes(String patternContent) { this.patternContent = patternContent; } } 

和function简化为:

 /* * Match given classAbbr with given RegEx pattern */ private void checkInvalidClassAbbr(String classAbbr, PatternTypes classAbbrPattern) { if (PatternTypes.ADDITIONAL_CHAR.equals(classAbbrPattern) || PatternTypes.UNICODE_BMP_CHARS.equals(classAbbrPattern)){ throw new MalFormedDNException("RegEx pattern:" + classAbbrPattern.name() + "is not allowed for Class Abbr"); } checkUnmatched(classAbbr, classAbbrPattern.getPatternContent(), CLASS_ABBR_VAR_NAME); } 

Hashmap被认为不是内存友好的,因此您可以将Enum用于此目的。

例:

 class EnumExample4{ enum Season{ WINTER(5), SPRING(10), SUMMER(15), FALL(20); private int value; private Season(int value){ this.value=value; } } public static void main(String args[]){ System.out.println(Season.WINTER.value); //This gives you 5 }} 

这将使您免于编写Switch Case或if语句。

对于switch语句的替代,我认为最好的解决方案是使用枚举 。 例如:考虑以下情况: –

  public enum EnumExample { OPTION1{ public double execute() { Log.info(CLASS_NAME, "execute", "The is the first option."); return void; } }, OPTION2{ public double execute() { Log.info(CLASS_NAME, "execute", "The is the second option."); return void; } }, OPTION3{ public double execute() { Log.info(CLASS_NAME, "execute", "The is the third option."); return void; }; public static final String CLASS_NAME = Indicator.class.getName(); public abstract void execute(); } 

上述枚举可以按以下方式使用:

 EnumExample.OPTION1.execute(); 

希望这可以帮助你们。

你想让我做什么? 为什么Switch-Case不够好?

快速回答是:使用if-else

  if () {} else if () {} ... else if () {} 

但我不会说它更好……

if (以及else ifelse )语句怎么样? 虽然switch只允许你使用相等的整数或枚举类型进行切换,但是if允许你使用任何布尔逻辑。

你总是可以用if-else if-else if-else if...替换一个开关if-else if-else if-else if... ,虽然我不明白为什么你想要。 根据上下文switch有时也可以用数组或散列图替换。

如果字符串是静态的,您可以创建一个ENUM。 然后切换它。