Рубрики
Без рубрики

Введение в шаблон нулевого объекта

Узнайте о шаблоне нулевого объекта и о том, как его реализовать в Java

Автор оригинала: Krzysztof Woyke.

1. Обзор

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

Как обычно, мы также приведем простой пример кода.

2. Шаблон Нулевого Объекта

В большинстве объектно-ориентированных языков программирования нам не разрешается использовать ссылку null . Вот почему мы часто вынуждены писать null проверки:

Command cmd = getCommand();
if (cmd != null) {
    cmd.execute();
}

Иногда, если количество таких операторов if становится большим, код может стать уродливым, трудночитаемым и подверженным ошибкам. Именно тогда шаблон Нулевого объекта может пригодиться.

Цель шаблона нулевого объекта состоит в том, чтобы свести к минимуму такого рода проверку null . Вместо этого мы можем идентифицировать поведение null и инкапсулировать его в тип, ожидаемый клиентским кодом. Чаще всего такая нейтральная логика очень проста – ничего не делать. Таким образом, нам больше не нужно иметь дело со специальной обработкой ссылок null .

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

Поскольку нулевые объекты не должны иметь никакого состояния, нет необходимости создавать идентичные экземпляры несколько раз. Таким образом, мы часто реализуем нулевые объекты как синглеты .

3. UML-диаграмма шаблона нулевого объекта

Давайте посмотрим на рисунок визуально:

Как мы видим, мы можем выделить следующих участников:

  • Клиенту требуется экземпляр Абстрактного объекта
  • AbstractObject определяет контракт Клиент ожидает – он также может содержать общую логику для реализующих классов
  • Реальный объект реализует Абстрактный объект и обеспечивает реальное поведение
  • Нулевой объект реализует Абстрактный объект и обеспечивает нейтральное поведение

4. Реализация

Теперь, когда у нас есть четкое представление о теории, давайте рассмотрим пример.

Представьте, что у нас есть приложение маршрутизатора сообщений. Каждому сообщению должен быть назначен действительный приоритет. Наша система должна направлять сообщения с высоким приоритетом на шлюз SMS, в то время как сообщения со средним приоритетом должны направляться в очередь JMS.

Время от времени, Однако, в наше приложение могут приходить сообщения с “неопределенным” или пустым приоритетом|/. Такие сообщения следует исключить из дальнейшей обработки.

Сначала мы создадим интерфейс Маршрутизатор :

public interface Router {
    void route(Message msg);
}

Далее давайте создадим две реализации вышеупомянутого интерфейса – ту, которая отвечает за маршрутизацию к SMS-шлюзу, и ту, которая будет направлять сообщения в очередь JMS:

public class SmsRouter implements Router {
    @Override
    public void route(Message msg) {
        // implementation details
    }
}
public class JmsRouter implements Router {
    @Override
    public void route(Message msg) {
        // implementation details
    }
}

Наконец, давайте реализуем наш нулевой объект:

public class NullRouter implements Router {
    @Override
    public void route(Message msg) {
        // do nothing
    }
}

Теперь мы готовы собрать все кусочки воедино. Давайте посмотрим, как может выглядеть пример клиентского кода:

public class RoutingHandler {
    public void handle(Iterable messages) {
        for (Message msg : messages) {
            Router router = RouterFactory.getRouterForMessage(msg);
            router.route(msg);
        }
    }
}

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

5. Когда следует использовать шаблон Нулевого объекта

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

Такой подход следует общим объектно-ориентированным принципам, таким как Скажи-не-Спрашивай .

Чтобы лучше понять, когда мы должны использовать шаблон нулевого объекта, давайте представим, что нам нужно реализовать CustomerDAO интерфейс, определенный следующим образом:

public interface CustomerDao {
    Collection findByNameAndLastname(String name, String lastname);
    Customer getById(Long id);
}

Большинство разработчиков вернули бы Коллекции.Пустой список() из Найти имя и фамилию() в случае, если ни один из клиентов не соответствует предоставленным критериям поиска. Это очень хороший пример следования шаблону Нулевых объектов.

В отличие от этого, get По идентификатору() должен вернуть клиенту указанный идентификатор. Кто-то, вызывающий этот метод, ожидает получить конкретную сущность клиента. В случае, если такого клиента не существует, мы должны явно вернуть null , чтобы сообщить, что с предоставленным идентификатором что-то не так.

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

6. Заключение

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

Как обычно, все примеры кода доступны на GitHub .