“if”声明与OO设计

时间:2010-10-22 05:58:41

标签: java design-patterns if-statement enumeration

我有枚举说ErrorCodes

public enum ErrorCodes { 
       INVALID_LOGIN(100),
       INVALID_PASSWORD(101),
       SESSION_EXPIRED(102) ...;

       private int errorCode;

       private ErrorCodes(int error){
              this.errorCode = error;
       }    //setter and getter and other codes
}

现在我用这个错误代码检查我的异常错误代码。如果这样做,我不想写,如果这样做的话。我如何解决这个问题(如果是块,写10+)

那种情况有没有设计模式?

由于

6 个答案:

答案 0 :(得分:7)

使用if语句或开关执行此操作,或者只是以某种方式将有问题的逻辑实现到ErrorCode中。

以OO方式,这一切都取决于您希望应用程序或系统对错误代码做出反应的方式。让我们说你只想输出一些对话框:

public doSomethingWithError() {

  ErrorCodes e = getError(); 
     // the source of error, or originator, returns the enum

  switch(e) {
    case ErrorCodes.INVALID_LOGIN:
      prompt('Invalid Login');
    case ErrorCodes.INVALID_PASSWORD:
      prompt('Invalid password');
    // and so on
  }

}

我们可以改为创建一个ErrorHandler类来代替它:

// We'll implement this using OO instead
public doSomethingWithError() {

  ErrorHandler e = getError(); 
    // the originator now returns an ErrorHandler object instead

  e.handleMessage();

}

// We will need the following abstract class:
public abstract class ErrorHandler {

   // Lets say we have a prompter class that prompts the message
   private Prompter prompter = new Prompter();

   public final void handleMessage() {
     String message = this.getMessage();
     prompter.prompt(message);
   } 

   // This needs to be implemented in subclasses because
   // handleMessage() method is using it.
   public abstract String getMessage();
}

// And you'll have the following implementations, e.g.
// for invalid logins:
public final class InvalidLoginHandler() {

  public final String getMessage() {
     return "Invalid login";
  }

}

// E.g. for invalid password:
public final class InvalidPasswordHandler() {
  public final String getMessage() {
    return "Invalid password";
  }
}

前一种解决方案易于实现,但随着代码变大而变得难以维护。后一种解决方案更复杂,(Template Method pattern后面的Open-Closed Principle),但是当您需要时(例如恢复资源或其他任何内容),您可以在ErrorHandler中添加更多方法。您也可以使用Strategy pattern实现此目的。

您不会完全使用条件语句,但在后者中,条件被推送到发生错误的代码部分。这样,您就不会在发起者和错误处理代码上对条件语句进行双重维护。

编辑:

如果您想这样做,请参阅this answer by Michael Borgwardtthis answer by oksayt了解如何在Java Enums上实现方法。

答案 1 :(得分:4)

Java枚举功能非常强大,允许按实例方法实现:

public enum ErrorCode { 
       INVALID_LOGIN {
        public void handleError() {
            // do something
        }
    },
       INVALID_PASSWORD {
        public void handleError() {
            // do something else
        }
    },
       SESSION_EXPIRED {
        public void handleError() {
            // do something else again
        }
    };

    public abstract void handleError();
}

然后您只需拨打errorCode.handleError();即可。但是,ErrorCode枚举是否真的适合该逻辑是值得怀疑的。

答案 2 :(得分:3)

正如Spoike所指出的,使用多态来选择正确的错误处理方法是一种选择。通过定义类层次结构,这种方法基本上将10+ if块推迟到JVM的虚方法查找。

但在进入一个完整的类层次结构之前,还要考虑使用enum方法。如果您计划在每种情况下执行的操作非常相似,则此选项很有效。

例如,如果您想为每个ErrorCode返回不同的错误消息,您只需执行以下操作:

// Note singular name for enum
public enum ErrorCode { 
   INVALID_LOGIN(100, "Your login is invalid"),
   INVALID_PASSWORD(101, "Your password is invalid"),
   SESSION_EXPIRED(102, "Your session has expired");

   private final int code;
   private final String 

   private ErrorCode(int code, String message){
          this.code = code;
          this.message = message;
   }

   public String getMessage() {
       return message;
   }
}

然后您的错误处理代码变为:

ErrorCode errorCode = getErrorCode();
prompt(errorCode.getMessage());

这种方法的一个缺点是,如果要添加其他案例,则需要修改枚举本身,而使用类层次结构,您可以添加新案例而无需修改现有代码。

答案 3 :(得分:2)

我相信你能做的最好的就是实施战略模式。这样,您在添加新枚举时不必更改现有类,但仍可以扩展它们。 (开闭原理)。

搜索策略模式和开放封闭原则。

答案 4 :(得分:0)

您可以针对枚举类型

创建错误代码(整数)的映射

修改

在此解决方案中,一旦准备好地图,您就可以在地图中查找错误代码,因此不需要if..else查找。

E.g。

Map<Integer, ErrorCodes> errorMap = new HashMap<Integer, ErrorCodes>();
for (ErrorCodes error : ErrorCodes.values()) {
     errorMap.put(error.getCode(), error);
}

现在,当您想检查来自您的应用程序的错误代码时,您需要做的就是,

ErrorCodes error = errorMap.get(erro_code_from_application);

因此不需要所有if..else。

您只需要以添加错误代码不需要更改其他代码的方式设置地图。地图的准备是一次性活动,可以在应用程序初始化期间链接到数据库,属性文件等

答案 5 :(得分:0)

在我看来,ErrorCodes作为枚举和switch语句分派错误处理没有任何问题。枚举和开关很好地配合在一起。

但是,也许您会发现以下内容(过度设计),请参阅an Example"Double dispatching" on Wikipedia。 假设要求:

  • 错误处理应该封装在自己的类
  • 错误处理应该是可替换的
  • 类型安全性:每当添加错误时,您都被迫在每个错误处理程序实现中添加错误处理。在一个(可能很多)开关状态中“忘记”错误是不可能的。

代码:

//Inteface for type-safe error handler
interface ErrorHandler {
    void handleInvalidLoginError(InvalidLoginError error);
    void handleInvalidPasswordError(InvalidLoginError error);
//One method must be added for each kind error. No chance to "forget" one.
}

//The error hierachy
public class AbstractError(Exception) {
    private int code;
    abstract public void handle(ErrorHandler);
}
public class InvalidLoginError(AbstractError) {
    private String additionalStuff;
    public void handle(ErrorHandler handler) {
        handler.handleInvalidLoginError(this);
    }   
    public String getAdditionalStuff();
}
public class InvalidPasswordError(AbstractError) {
    private int code;
    public void handle(ErrorHandler handler) {
        handler.handleInvalidPasswordError(this);
    }
}

//Test class
public class Test {
    public void test() {
        //Create an error handler instance.
        ErrorHandler handler = new LoggingErrorHandler();

        try {
            doSomething();//throws AbstractError
        }
        catch (AbstractError e) {
            e.handle(handler);
        }
    }
}