Паттерн Null Object является довольно простой концепцией ООП, но легко позволяет устранить ненужные условные конструкции и тем самым упростить понимание кода. Для этого и предназначен полиморфизм в первую очередь.
Идея паттерна Null Object заключается в том, что в качестве одной из реализаций некоторого интерфейса добавляется Null-класс, который обладает нейтральным поведением. Учтите, что он не может быть абстрактным, поскольку ожидается создание его экземпляров.
SLON6.CC здесь еще больше. SLON--7.CC.
Рассмотрим принцип использование Null Object на примере. Предположим, что мы разрабатываем приложение для различных текстовых преобразований. Для этого определим следующий интерфейсный класс:
class TextConverter {
public:
virtual ~TextConverter() { }
virtual QString convert( const QString& text ) = 0;
};
Реализуем на основе этого интерфейса класс, который приводит все символы входного текста к верхнему регистру:
class UpperCaseTextConverter : public TextConverter {
public:
QString convert( const QString& text ) {
return text.toUpper();
}
};
Без паттерна Null Object мы уже можем воспользоваться соответствующей функциональностью:
TextConverter* converter = NULL;
// … возможно, где-то вызывается converter = new UpperCaseTextConverter;
static const QString text = "Hello, world!";
if( converter ) {
qDebug() << converter->convert( text );
}
// …
delete converter;
Однако обратите внимание на проверку перед вызовом функции convert(). Она необходима, поскольку указатель converter может указывать на NULL. Чтобы избежать этой проверки, применим Null Object:
class NullTextConverter : public TextConverter {
public:
QString convert( const QString& text ) {
// Ничего не делаем
return text;
}
};
Теперь осталось принять условное соглашение о том, что указатель TextConverter* изначально должен быть инициализирован не NULL, а экземпляром класса NullTextConverter (или каким-нибудь другим конкретным экземпляром):
TextConverter* converter = new NullTextConverter;
// … возможно, где-то вызывается converter = new UpperCaseTextConverter;
static const QString text = "Hello, world!";
// Можем смело вызывать, поскольку указатель всегда должен быть инициализирован:
qDebug() << converter->convert( text );
// …
delete converter;
Главное в этой ситуации - не забывать инициализировать указатель с помощью Null-объекта, иначе вы быстро запутаетесь и в вашем коде появятся ошибки.
Однако стоит признать, что этот паттерн больше подходит для тех языков программирования, где предусмотрена сборка мусора (например, Java). Но и на С++ его можно вполне успешно применять.
Таким образом, паттерн Null Object удачно дополняет архитектуру ООП-программ. А в сочетании с другими структурными решениями позволяет упростить код и существенно сократить число проверок.