空对象模式不是一个GoF设计模式,但是它出现非常频繁足以被认为是设计模式。它的好处如下:
返回一个对象或null的方法应该返回一个对象或NullObject。NullObjects简化了样板代码,如if (!is_null($obj)) {$obj->callSomething();}只需要$obj->callSomething();通过消除客户端代码中的条件签入。
Service.php
<?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
<?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
<?php
declare(strict_types=1);
namespace DesignPatterns\Behavioral\NullObject;
class PrintLogger implements Logger
{
public function log(string $str)
{
echo $str;
}
}
NullLogger.php
<?php
declare(strict_types=1);
namespace DesignPatterns\Behavioral\NullObject;
class NullLogger implements Logger
{
public function log(string $str)
{
// do nothing
}
}
Tests/LoggerTest.php
<?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();
}
}