Null object (шаблон проектирования)
В объектно-ориентированном программировании Null Object — это объект с определенным нейтральным («null») поведением. Шаблон проектирования Null Object описывает использование таких объектов и их поведение (или отсутствие такового). Впервые опубликован в серии книг Pattern Languages of Program Design.[1]
Описание
[править | править код]В таких объектно-ориентированных языках как Java или C# объекты могут иметь значение NULL. Ссылки на такие объекты нуждаются в проверке на NULL-значение перед использованием, так как методы класса «нулевого» объекта, как правило, не могут вызываться.
Целью Null-object'а является инкапсулирование отсутствия объекта путём замещения его другим объектом, который ничего не делает.
Данный шаблон проектирования рекомендуется использовать, когда:
- Объект требует взаимодействия с другими объектами. Null Object не устанавливает нового взаимодействия — он использует уже установленное взаимодействие.
- Какие-то из взаимодействующих объектов должны бездействовать.
- Требуется абстрагирование «общения» с объектами, имеющими NULL-значение.[2]
Плюсы
[править | править код]- Снижаются шансы на ошибку — не произойдёт разыменование нулевого указателя, потому что его нет.
Минусы
[править | править код]- Могут неоправданно включаться дополнительные механизмы языка программирования вроде выделения памяти и виртуального полиморфизма.
- Если интерфейс сложный, нужно много нетворческого кода.
- Если перед вызовом происходит сложная подготовка, всё равно приходится спрашивать у объекта, делает ли он что-то — но это лишь дополнительная оптимизация, не ведущая к моментальному отказу программы.
// Для ясности функции с разными сигнатурами зовутся разными именами.
// Тут никаких вопросов.
logger.put("Program started.");
// Запускается тяжёлый format, даже если журнала нет
logger.put(std::format("a={}, b={}", a, b));
// Тут format запускается, только если logger реально пишет
if (logger.isWriting()) {
logger.put(std::format("a={}, b={}", a, b));
}
// Два способа решить, со своими достоинствами и недостатками
logger.format("a={}, b={}", a, b);
logger.putObj(LazyFormat{"a={}, b={}", a, b});
Структура
[править | править код]На диаграмме классов в языке UML шаблон проектирования представлен следующим образом:
Примеры
[править | править код]Пример на C#
/*
* Пример применения шаблона Null Object:
*/
void Main()
{
AbstractEntity realEntity = new RealEntity();
realEntity.doSomething(); // RealEntity::doSomething
AbstractEntity unknownEntity = new NullEntity();
unknownEntity.doSomething(); // no output
}
// Define other methods and classes here
public abstract class AbstractEntity
{
public abstract void doSomething();
}
public class RealEntity : AbstractEntity
{
public override void doSomething()
{
Console.WriteLine("RealEntity::doSomething");
}
}
public class NullEntity : AbstractEntity
{
public override void doSomething()
{
// doing nothing
}
}
Пример на PHP
/*
* Пример применения шаблона Null Object:
*/
declare(strict_types=1);
namespace DesignPatterns\Behavioral\NullObject;
class Service
{
public function __construct(private Logger $logger)
{
}
/**
* do something ...
*/
public function doSomething()
{
// notice here that you don't have to check if the logger is set with eg. is_null(), instead just use it
$this->logger->log('We are in ' . __METHOD__);
}
}
/**
* Key feature: NullLogger must inherit from this interface like any other loggers
*/
interface Logger
{
public function log(string $str);
}
class PrintLogger implements Logger
{
public function log(string $str)
{
echo $str;
}
}
class NullLogger implements Logger
{
public function log(string $str)
{
// do nothing
}
}
$servicePrint = new Service(new PrintLogger());
$servicePrint->doSomething(); // 'We are in DesignPatterns\Behavioral\NullObject\Service::doSomething'
$serviceNull = new Service(new NullLogger());
$serviceNull->doSomething(); // (do nothing)
Пример на Java
/*
* Pattern Null object.
*/
public class Main {
public static void main(String[] args) {
AbstractEntity realEntity = new RealEntity();
realEntity.doSomething(); // RealEntity::doSomething
AbstractEntity unknownEntity = new NullEntity();
unknownEntity.doSomething(); // no output
}
}
abstract class AbstractEntity {
public abstract void doSomething();
}
class RealEntity extends AbstractEntity {
@Override
public void doSomething() {
System.out.println("RealEntity::doSomething");
}
}
class NullEntity extends AbstractEntity {
@Override
public void doSomething() {
}
}
Пример на Python
# Pattern Null object.
class AbstractEntity:
def doSomething(self):
pass
class RealEntity(AbstractEntity):
def doSomething(self):
print("RealEntity.doSomething")
class NullEntity(AbstractEntity):
def doSomething(self):
pass
def main():
real_entity = RealEntity()
real_entity.doSomething()
unknown_entity = NullEntity()
unknown_entity.doSomething()
if __name__ == "__main__":
main()
Пример на Ruby
[править | править код]module NullObject
# AbstractEntity
class AbstractEntity
def doSomething
raise NoMethodError.new
end
end
# RealEntity
class RealEntity < AbstractEntity
def doSomething
puts "RealEntity > Do Something"
end
end
# NullEntity
class NullEntity < AbstractEntity
def doSomething
nil
end
end
end
# Client
module Client
include NullObject
realEntity = RealEntity.new
nullEntity = NullEntity.new
puts "RealEntity:" # => RealEntity
realEntity.doSomething # => RealEntity > Do Something
puts "NullEntity:" # => NullEntity:
nullEntity.doSomething # not output
end
Примечания
[править | править код]- ↑ Woolf, Bobby. Pattern Languages of Program Design 3 (неопр.) / Martin, Robert; Riehle, Dirk; Buschmann, Frank. — Addison-Wesley, 1998.
- ↑ http://sourcemaking.com/design_patterns/null_object Архивная копия от 15 июня 2012 на Wayback Machine SourceMaking Tutorial
Ссылки
[править | править код]- Jeffrey Walkers' account of the Null Object Pattern
- Martin Fowlers' description of Special Case, a slightly more general pattern
- Null Object Pattern Revisited
- Introduce Null Object refactoring
В другом языковом разделе есть более полная статья Null object pattern (англ.). |
Это заготовка статьи о программном обеспечении. Помогите Википедии, дополнив её. |