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
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
<?php

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__);
    }
}

Logger.php

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
<?php

declare(strict_types=1);

namespace DesignPatterns\Behavioral\NullObject;

/**
 * Key feature: NullLogger must inherit from this interface like any other loggers
 */
interface Logger
{
    public function log(string $str);
}

PrintLogger.php

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
<?php

declare(strict_types=1);

namespace DesignPatterns\Behavioral\NullObject;

class PrintLogger implements Logger
{
    public function log(string $str)
    {
        echo $str;
    }
}

NullLogger.php

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
<?php

declare(strict_types=1);

namespace DesignPatterns\Behavioral\NullObject;

class NullLogger implements Logger
{
    public function log(string $str)
    {
        // do nothing
    }
}

3.7.5. Testy

Tests/LoggerTest.php

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?php

declare(strict_types=1);

namespace DesignPatterns\Behavioral\NullObject\Tests;

use DesignPatterns\Behavioral\NullObject\NullLogger;
use DesignPatterns\Behavioral\NullObject\PrintLogger;
use DesignPatterns\Behavioral\NullObject\Service;
use PHPUnit\Framework\TestCase;

class LoggerTest extends TestCase
{
    public function testNullObject()
    {
        $service = new Service(new NullLogger());
        $this->expectOutputString('');
        $service->doSomething();
    }

    public function testStandardLogger()
    {
        $service = new Service(new PrintLogger());
        $this->expectOutputString('We are in DesignPatterns\Behavioral\NullObject\Service::doSomething');
        $service->doSomething();
    }
}