Null Object Pattern, чтобы избежать проверок Null? - PullRequest
6 голосов
/ 17 октября 2010

В последнее время я столкнулся с шаблоном проектирования Null Object, и мои коллеги говорят, что его можно использовать, чтобы покончить с проверками нулевого указателя, которые встречаются во всем коде.

например, предположим, что класс DAO возвращает информацию о Customer (в объекте значения с именем CustomerVO). Мой основной класс должен извлечь firstName и emailId и отправить письмо клиенту.

...
CustomerVO custVO = CustomerDAO.getCustomer(customerID);
if(custVO != null) { // imp, otherwise we may get null ptr exception in next line
     sendEmail(custVO.getFirstName(), custVO.getEmailID());
}
...

Это очень простой пример, но такие нулевые проверки могут быстро распространиться по всему коду в зависимости от сложности объектов-значений.

У меня есть две проблемы с проверкой нуля, - они имеют тенденцию делать код безобразным и трудным для чтения - менее опытные разработчики ставят ненужные нулевые проверки, когда на самом деле они должны генерировать исключения. например, в приведенном выше коде было бы лучше выбросить исключение из самого getCustomer (), потому что, если он не может найти информацию о клиенте для данного CustID, это указывает, что CustID был недействительным.

Хорошо, возвращаясь к шаблону нулевого объекта, можем ли мы использовать нулевой объект CustomerVO, чтобы скрыть проверку нуля?

CustomerVO {
   String firstName = "";
   String emailID = ""; 
}

Не имеет смысла. что ты думаешь?

И что вы делаете, чтобы минимизировать нулевые проверки в вашем приложении.

Ответы [ 5 ]

3 голосов
/ 17 октября 2010

Несмотря на то, что в шаблоне нулевого объекта он используется, вам все равно потребуется здесь проверить, в противном случае вы попытаетесь sendEmail() указать адрес электронной почты, который является пустой строкой (или вы нажимаете на проверку в sendEmail(), который можно так же легко проверить на null).

В этом случае действительно полезен шаблон нулевого объекта, если в классе CustomerVO реализован метод sendEmail(). тогда вы можете просто объединить вызовы вместе, так как контракт getCustomer() гарантирует, что ссылка null не будет возвращена:

CustomerDAO.getCustomer(customerID).sendEmail();

В этом случае метод sendEmail() будет проверять, что его попросили воздействовать на специальный «нулевой объект», и просто ничего не делать (или делать то, что подходит).

2 голосов
/ 17 октября 2010

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

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

1 голос
/ 15 мая 2012

У меня проблема с этим типом кода, который является распространенным шаблоном. Вам вообще не нужны нулевые проверки, если вы разлагаете то, что на самом деле делаете. Проблема здесь, на мой взгляд, в том, что вы нарушаете SRP.

Метод CustomerVO custVO = CustomerDAO.getCustomer(customerID); делает две вещи.

Во-первых, он возвращает клиента, если он существует, и, во-вторых, возвращает ноль, если такого клиента нет. Это две разные операции, которые должны быть закодированы как таковые.

Лучший подход был бы:

bool customerExists = CustomerDAO.exists(customerID);

if (customerExists)
{
  CustomerVO custVO = CustomerDAO.getCustomer(customerID);
  sendEmail(custVO.getFirstName(), custVO.getEmailID());
}
else
{
   // Do whatever is appropriate if there is no such customer.
}

}

Итак, разделите метод на два: один, который проверяет, существует ли запрошенный объект, а второй, который фактически его получает. Нет необходимости в каких-либо исключениях, и дизайн и семантика очень понятны (что, на мой взгляд, с шаблоном «не существует, возвращает ноль» не так). Кроме того, в этом подходе метод CustomerDAO.getCustomer(customerID) выдает ArgumentException, если запрошенный клиент не существует. В конце концов, вы попросили Customer, а его нет.

Кроме того, на мой взгляд, ни один метод не должен возвращать null. Null явно означает: «Я не знаю, каков правильный ответ, у меня нет значения для возврата». Null это не значение, это отсутствие значения. Спросите себя: «Почему я возвращаю то, что, как я знаю, на самом деле не должно происходить? Ваш метод GetCustomer должен возвращать Customer, очевидно. Если вы вернете null, вы просто возьмете на себя ответственность за то, что нужно сделать, сделайте резервную копию цепочки вызовов и разорвите контракт. Если есть значимое значение по умолчанию, используйте его, но выбрасывание исключения может заставить вас задуматься о правильном дизайне.

1 голос
/ 17 октября 2010

Должен ли ваш метод getCustomer генерировать исключение, если клиент не найден, а не возвращать ноль?

Ответ, конечно, состоит в том, что это зависит: должно ли это почти никогда быть в том случае, если идентификатор клиента не существует? Другими словами, это исключительное обстоятельство? Если так, то исключение уместно.

Однако на уровне доступа к данным часто совершенно нормально, когда чего-то не существует. В этом случае лучше не бросать, поскольку это не неожиданное, исключительное обстоятельство.

«Возвращать ненулевой объект с пустыми полями», вероятно, не лучше. Как вы узнаете, является ли возвращенный объект «действительным» или нет, без добавления теперь некоторого проверочного кода, который, вероятно, хуже, чем нулевая проверка?

Итак, если это может быть нормальное состояние, что что-то извлекаемое не существует, шаблон проверки на ноль, вероятно, является лучшим. Если это что-то неожиданное, то лучше использовать метод доступа к данным, генерирующий исключение NotFound.

0 голосов
/ 30 октября 2015

Имя - шаблон проектирования объекта NULL, а не шаблон проектирования проверки NULL.Нулевой объект означает отсутствие объекта.Это следует использовать, когда у вас есть объекты, работающие в СОТРУДНИЧЕСТВЕ.В вашем случае вы проверяете существование объекта, для которого должна выполняться проверка NULL.

Шаблон проектирования NULL не предназначен для замены обработки исключений NULL.Это одно из побочных преимуществ шаблона проектирования NULL, но цель состоит в том, чтобы обеспечить поведение по умолчанию.

Проверки NULL не следует заменять объектами шаблона проектирования NULL, поскольку это может привести к автоматическим дефектам в приложении.

См. Приведенную ниже статью, в которой подробно рассматриваются шаблон проектирования DO и Donts of NULL.

http://www.codeproject.com/Articles/1042674/NULL-Object-Design-Pattern

...