3.7. Pusty obiekt (Null Object)

3.7.1. Przeznaczenie

Pusty Obiekt nie jest wzrorcem zaproponowanym przez Bandę Czterech, niemniej jednak jest na tyle popularny, że może być uznany za wzorzec. Użycie tego wzorca niesie następujące korzyści:

  • uproszcza kodu programu,

  • zmniejsza prawdopodobieństwo wystąpienia błędu null pointer exception,

  • eliminuje zbędne lub powtarzające się warunki, które wpływają na zmniejszenie liczby przypadków testowych,

Metoda, która zwraca obiekt lub null powinna zwracać obiekt lub Obiekt Pusty (NullObject). NullObject w znaczący sposób upraszcza kod z postaci if (!is_null($obj)) { $obj->callSomething(); } do $obj->callSomething(); poprzez eliminację warunku w kodzie klienta.

3.7.2. Przykłady

  • Null logger or null output to preserve a standard way of interaction between objects, even if the shouldn’t do anything

  • Obsługa NULL we wzrocu Łańcuch zobowiązań.

  • Polecenie NULL we wzorcu Polecenie.

3.7.3. Diagram UML

Alt NullObject UML Diagram

3.7.4. Kod

Ten kod znajdziesz również na GitHub.

Service.php

 1<?php
 2
 3declare(strict_types=1);
 4
 5namespace DesignPatterns\Behavioral\NullObject;
 6
 7class Service
 8{
 9    public function __construct(private Logger $logger)
10    {
11    }
12
13    /**
14     * do something ...
15     */
16    public function doSomething()
17    {
18        // notice here that you don't have to check if the logger is set with eg. is_null(), instead just use it
19        $this->logger->log('We are in ' . __METHOD__);
20    }
21}

Logger.php

 1<?php
 2
 3declare(strict_types=1);
 4
 5namespace DesignPatterns\Behavioral\NullObject;
 6
 7/**
 8 * Key feature: NullLogger must inherit from this interface like any other loggers
 9 */
10interface Logger
11{
12    public function log(string $str);
13}

PrintLogger.php

 1<?php
 2
 3declare(strict_types=1);
 4
 5namespace DesignPatterns\Behavioral\NullObject;
 6
 7class PrintLogger implements Logger
 8{
 9    public function log(string $str)
10    {
11        echo $str;
12    }
13}

NullLogger.php

 1<?php
 2
 3declare(strict_types=1);
 4
 5namespace DesignPatterns\Behavioral\NullObject;
 6
 7class NullLogger implements Logger
 8{
 9    public function log(string $str)
10    {
11        // do nothing
12    }
13}

3.7.5. Testy

Tests/LoggerTest.php

 1<?php
 2
 3declare(strict_types=1);
 4
 5namespace DesignPatterns\Behavioral\NullObject\Tests;
 6
 7use DesignPatterns\Behavioral\NullObject\NullLogger;
 8use DesignPatterns\Behavioral\NullObject\PrintLogger;
 9use DesignPatterns\Behavioral\NullObject\Service;
10use PHPUnit\Framework\TestCase;
11
12class LoggerTest extends TestCase
13{
14    public function testNullObject()
15    {
16        $service = new Service(new NullLogger());
17        $this->expectOutputString('');
18        $service->doSomething();
19    }
20
21    public function testStandardLogger()
22    {
23        $service = new Service(new PrintLogger());
24        $this->expectOutputString('We are in DesignPatterns\Behavioral\NullObject\Service::doSomething');
25        $service->doSomething();
26    }
27}