一个类是否应该从它不知道的类中捕获异常?

时间:2013-02-12 04:55:37

标签: oop

我在MVC框架中编写了一些类似于:

的代码
class Controller_Test extends Controller
{
   public function action_index()
   {
      $obj = new MyObject();
      $errors = array();

      try
      {
         $results = $obj->doSomething();
      }
      catch(MyObject_Exception $e)
      {
         $e->getErrors();
      }
      catch(Exception $e)
      {
         $errors[] = $e->getMessage();
      }
}

我的朋友认为Controller应该对MyObject一无所知,因此我不应该捕获MyObject_Exception。

他认为代码应该做这样的事情:

class Controller_Test extends Controller
{
   public function action_index()
   {
      $obj = new MyObject();
      $errors = array();

      if($obj->doSomething())
      {
         $results = $obj->getResults();
      }
      else
      {
         $errors = $obj->getErrors();
      }
}

我绝对理解他的方法,但感觉好像国家管理会导致意想不到的副作用。

什么是正确的或首选的方法?

编辑:错误地将$ obj-> getErrors()放在MyObject_Exception catch子句中而不是$ e-> getErrors();

3 个答案:

答案 0 :(得分:1)

一般来说,我会说重要的是控制器是否理解异常的含义并且能够正确处理它。在许多情况下(如果不是大多数情况下),控制器将不知道如何正确处理异常,因此应该捕获并处理它。

另一方面,可以合理地允许控制器理解某些特定异常,例如“DatabaseUnavailableException”,即使它不知道MyObject如何或为什么使用数据库。可能会允许控制器重试MyObject一次,但不知道MyObject的实施方式。

答案 1 :(得分:1)

关于异常与返回错误代码的争论是漫长而血腥的。

他的论点在于,通过使用getErrors()函数,你学习有关对象的信息。如果这是你使用布尔返回表示成功的原因,那么你错了。为了使Controller能够正确处理错误,它必须知道它正在触摸的对象以及具体的错误是什么。这是网络错误吗?内存错误? 必须以某种方式了解。

我更喜欢异常模型,因为它更干净,允许我以更加可控的方式处理更多错误。它还为与要传递的例外相关的数据提供了明确的方法。

但是,我不同意你使用像getErrors()这样的函数。任何有助于我处理它的异常的数据都应包含在异常中。我不应该再去寻找对象来获取有关出错的信息。

网络连接超时了吗?该异常应包含它尝试连接的主机/端口,等待的时间以及来自较低网络级别的任何数据。

让我们在示例中执行此操作(在psuedo c#中):

public class NetworkController {
    Socket MySocket = null;
    public void EstablishConnection() {
        try {
            this.MySocket = new Socket("1.1.1.1",90);
            this.MySocket.Open();

        } catch(SocketTimeoutException ex) {
            //Attempt a Single Reconnect
        }
        catch(InvalidHostNameException ex) {
            Log("InvalidHostname");
            Exit();
        }

    }
}

使用他的方法:

public class NetworkController {
    Socket MySocket = null;
    public Boolean EstablishConnection() {
        this.MySocket = new Socket("1.1.1.1",90);
        if(this.MySocket.Open()) {
            return true;
        } else {
            switch(this.MySocket.getError()) {
                case "timeout":
                    // Reattempt
                    break;
                case "badhost":
                    Log("InvalidHostname");
                    break;
            }
        }
    }
}

最终,您需要知道对象发生了什么,以了解如何响应它,并且使用一些复杂的if语句集或switch-case来确定它是没有意义的。使用例外并爱他们。

编辑:我不小心在后半句。

答案 2 :(得分:1)

首先,控制器不是用于处理类引发的基础异常。

即使有人出现控制器,也应该停止在底层错误中说错了。

通过这种方式,我们确保控制器真正做到并且只做流控制工作。

为控制器提供一些输出的其他类应该没有错误,除非错误是特定于控制器的。