Об’єкт Null (англ. Null Object) - це об’єкт з певною нейтральною (“null”) поведінкою.
Шаблон проєктування Null Object визначає використання таких об’єктів та його поведінку (чи її відсутність).
Null Object - не шаблон із книги Банди Чотирьох, але схема, яка з’являється досить часто, щоб вважатися шаблоном. Вона має такі переваги:
- Клієнтський код спрощується;
- Зменшує шанс винятків через нульові покажчики (та помилок PHP різного рівня);
- Менше додаткових умов - менше тест кейсів.
Методи, які повертають об’єкт або Null, натомість мають повернути об’єкт NullObject.
Це спрощений формальний код, який усуває необхідність перевірки if (!is_null($obj)) { $obj->callSomething(); }
,
замінюючи її на звичайний виклик $obj->callSomething();
.
-
NullWorker.php
<?php namespace DesignPatterns\Behavioral\NullObject; class NullWorker implements WorkerInterface { const MSG = 'NULL OBJECT'; public function isNull(): bool { return true; } public function makeSomethink() { return self::MSG; } }
-
Worker.php
<?php namespace DesignPatterns\Behavioral\NullObject; class Worker implements WorkerInterface { const MSG = 'Worker make somethink'; public function isNull(): bool { return false; } public function makeSomethink() { return self::MSG; } }
-
WorkerInterface.php
<?php namespace DesignPatterns\Behavioral\NullObject; interface WorkerInterface { public function isNull(): bool; public function makeSomethink(); }
-
WorkerPool.php
<?php namespace DesignPatterns\Behavioral\NullObject; class WorkerPool { /** * @var WorkerInterface[] */ protected $pool = []; public function __construct(...$workers) { $this->pool = $workers; } public function getPool(int $key): WorkerInterface { return $this->pool[$key] ?? new NullWorker(); } public function makeSomethink(int $key = null) { return $this->getPool($key)->makeSomethink(); } }
Test case:
WorkerPoolTest.php
<?php
namespace DesignPatterns\Tests\Behavioral\NullObject;
use DesignPatterns\Behavioral\NullObject\NullWorker;
use DesignPatterns\Behavioral\NullObject\Worker;
use DesignPatterns\Behavioral\NullObject\WorkerPool;
class WorkerPoolTest extends \PHPUnit_Framework_TestCase
{
public function testNullObject()
{
$worker = new Worker();
$pool = new WorkerPool($worker);
$this->assertEquals(Worker::MSG, $pool->makeSomethink(0));
$this->assertEquals(false, $worker->isNull());
$this->assertEquals(false, $pool->getPool(0)->isNull());
$this->assertEquals(NullWorker::MSG, $pool->makeSomethink(1));
$this->assertEquals(true, $pool->getPool(1)->isNull());
}
}