2012-11-27 2 views
1

Предположим, у нас есть иерархия объектов, построенная по композиции. Есть ли какой-либо шаблон для регистрации ошибок бизнес-логики внутри внутренних объектов и передачи их в верхние объекты?Как эффективно справляться с ошибками бизнес-логики?

Я просто устал от всех этих addErrors, getErrors на каждом уровне, и я чувствую, что я делаю что-то неправильно.

Я знаю об исключениях, но я не имею в виду, как их использовать в таком случае. Ошибка бизнес-логики технически не является критической ситуацией, что должно привести к прерыванию выполнения программы. На самом деле прерывание не допускается вообще, потому что нам нужно зарегистрировать ошибку и просто двигаться дальше.

Спасибо заранее, чтобы поделиться своей мудростью и знаниями)

небольшой фрагмент кода, чтобы проиллюстрировать эту проблему:

class ErrorContainer { 
    private $errors = array(); 
    function addError($error) { if (!is_array($error)) { $this->errors[] = $error;} else { $this->errors = array_merge($this->errors, $error); } } 
    function getErrors() { return $this->errors[]; } 
    function hasErrors() { return !empty($this->errors); } 
} 

class Processor extends ErrorContainer { 
    function process($account_id, $orders) { 
     $account = new Account(); 
     if (!$account->loadById($account_id)) { $this->addErrors($account->getErrors);} 

     foreach ($orders as $order_id) { 
      $order = new Order(); 
      if (!$order->loadById($order_id)) { $this->addErrors($order->getErrors);} 
     } 
    } 

    return $this->hasErrors(); 
} 

class Account extends ErrorContainer { 
    function loadById($account_id) { 
     $account = select_from_database($account_id); 
     if (!$account) { $this->addError("Account is missing"); } 
     if (!$account['active']) { $this->addError("Account is inactive"); } 
     // and so on, some checks may add errors in a cycle 

     return $this->hasErrors(); 
    } 
} 

class Order extends ErrorContainer {} // very similar to Account, but has its own checks 

//Usage: 

$errors = array(); 
$items = load_items_from_xml($xml); 
foreach ($items as $item) { 
    $processor = new Processor(); 
    if (!$processor->process($item['account_id'], $item['orders'])) { 
     $errors = array_merge($errors, $processor->getErrors()); 
    } 
} 
+0

Это может быть хорошим вопросом для http://codereview.stackexchange.com/ –

ответ

0

Исключения не используются только в критических ситуациях, но в вашем случае это не такая плохая идея использовать систему ошибок, которую вы сейчас имеете. Вы можете использовать константы вместо текста для ошибок и определить все возможные константы ошибок в каждом классе.

class Account extends ErrorContainer { 
    const ERR_ACC_MISSING = 0; 
    const ERR_ACC_INACTIVE = 1; 
    function loadById($account_id) { 
     $account = select_from_database($account_id); 
     if (!$account) { $this->addError(ERR_ACC_MISSING); } 
     if (!$account['active']) { $this->addError(ERR_ACC_INACTIVE); } 
     // and so on, some checks may add errors in a cycle 

     return $this->hasErrors(); 
    } 
} 
+0

Просмотра Кода Спасибо за ваше предложение о постоянных. Я согласен, что это подходящее место для них). Что касается основной проблемы - я надеялся, что существует какая-то модель, которая допускает ошибки до любовного пузыря до головного объекта. Или, может быть, шаблон, который предполагает наличие некоторого внешнего контейнера для хранения/добавления ошибок. –

+0

Вы не можете объединить все ошибки вместе и обрабатывать их одновременно. Такое же ограничение применимо и к обработке исключений. Вам необходимо обработать ошибки как можно раньше. – Michael

+0

Что делать, если у нас нет способа (или не нужно) обрабатывать ошибки, но необходимо уведомить кого-нибудь обо всех ошибках? Или обработка ошибок откладывается до некоторого момента, когда оператор обрабатывает их вручную? –

Смежные вопросы