3.6. Null Object

3.6.1. Rôle

NullObject n’est pas un patron de conception du GoF mais un schéma qui apparaît suffisamment fréquemment pour être considéré comme un patron. Il présente les avantages suivants :

  • Le code client est simplifié

  • Réduit le risque d’exceptions de pointeur null

  • Moins de conditions exigent moins de cas de test

Les méthodes renvoyant un objet ou null devraient plutôt renvoyer un objet ou NullObject. Les NullObjects simplifient le code passe-partout tel que if (!is_null($obj)) { $obj->callSomething() ; } en le remplaçant par ``$obj->callSomething() ; ``en éliminant la vérification conditionnelle dans le code client.

3.6.2. Exemples

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

  • Null handler dans un modèle de chaîne de responsabilités

  • Null command dans un patron Command

3.6.3. Diagramme UML

Alt NullObject UML Diagram

3.6.4. Code

Vous pouvez également trouver ce code sur GitHub

Service.php

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php declare(strict_types=1);

namespace DesignPatterns\Behavioral\NullObject;

class Service
{
    private Logger $logger;

    public function __construct(Logger $logger)
    {
        $this->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
<?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
<?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
<?php declare(strict_types=1);

namespace DesignPatterns\Behavioral\NullObject;

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

3.6.5. Test

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