3.7. Objeto Nulo (Null Object)

3.7.1. Objetivo

Objeto Nulo (Null Object) não é um padrão de projeto GoF, mas um esquema o qual aparece com frequencia suficiente para ser considerado um padrão. Ele tem os seguintes benefícios:

  • Código do cliente é simplificado
  • Reduz a chance de exceções de ponto nulo (null pointer exceptions)
  • Menores condicionais requerem menos casos de teste

Métodos que retornam um objeto ou nulo devem ao invés disso, retornar um objeto ou NullObject. NullObjecté simplesmente código boilerplate como if (!is_null($obj)) { $obj->callSomething(); } para apenas $obj->callSomething(); eliminando então a checagem condicional no código cliente.

3.7.2. Exemplos

  • Log nulo ou saída nula para preservar uma forma padrão de interação entre objetos, mesmo que não devam fazer nada
  • manipulador nulo em um padrão de Cadeia de Responsabilidades (Chain of Responsibilities)
  • commando nulo em um padrão Comando (Command)

3.7.3. Diagrama UML

Alt NullObject UML Diagram

3.7.4. Código

Você também pode encontrar este código no 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. Teste

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