Java中Switch Case的替代方案

时间:2009-09-15 07:25:50

标签: java conditional-statements

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

14 个答案:

答案 0 :(得分:26)

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

您可以选择重构: Replace conditional with polymorphism.

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

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

<强> BEFORE

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语句会出现问题:

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

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

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

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

所以你会有这样的事情:

<强> AFTER

   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与节点等。

  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 ){
           //  ....
        }
   }

答案 1 :(得分:16)

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

Map<String,Object> map = new HasMap<String,Object>();
// ... 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(); }

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

答案 2 :(得分:5)

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

答案 3 :(得分:1)

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

答案 4 :(得分:1)

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

public interface Task<T>
     {
     public void doSomething(T context);
     }

public Class SwitchCase<T>
     {
     Map<Integer,Task<T>> tasks;
     Task<T> defaultTask;

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

答案 5 :(得分:1)

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

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

答案 6 :(得分:1)

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

在重构之前我有枚举PatternTypes

public enum PatternTypes {

    ALPHA_CHAR, ALPHANUMERIC_CHAR, ADDITIONAL_CHAR, UNICODE_BMP_CHARS
}

和功能:

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;
    }
}

和功能简化为:

/*
     * 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);

    }

答案 7 :(得分:1)

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语句。

答案 8 :(得分:1)

对于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();

希望这可以帮助你们。

答案 9 :(得分:0)

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

快速回答是:使用if-else

答案 10 :(得分:0)

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

但我不会说它更好......

答案 11 :(得分:0)

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

答案 12 :(得分:0)

您总是可以用if-else if-else if-else if...替换开关,但我不明白您为什么要这样做。根据上下文switch,有时也可以用数组或散列图代替。

答案 13 :(得分:0)

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

相关问题