Merge branch 'nullobject-pattern'

This commit is contained in:
Trismegiste 2013-05-13 21:50:25 +02:00
commit 397e18da8b
5 changed files with 139 additions and 0 deletions

View File

@ -0,0 +1,16 @@
<?php
/*
* DesignPatternPHP
*/
namespace DesignPatterns\NullObject;
/**
* LoggerInterface is a contract for logging something
*/
interface LoggerInterface
{
public function log($str);
}

38
NullObject/NullLogger.php Normal file
View File

@ -0,0 +1,38 @@
<?php
/*
* DesignPatternPHP
*/
namespace DesignPatterns\NullObject;
/**
* NullOutput is a example of NullObject pattern. It is not formely a Design
* Pattern by the GoF but it's a schema which appears frequently enough to
* be a pattern. Futhermore it is a really good pattern in my opinion :
* - the code in the client is simple
* - it reduces the chance of null pointer exception
* - less "if" => less test cases
*
* The purpose : every time you have a method which returns an object or null,
* you should return an object or a "NullObject". With NullObject, you don't need
* statement like "if (!is_null($obj)) { $obj->callSomething(); }" anymore.
*
* In this case, this a logger which does nothing. Other examples :
* - null logger of symfony profiler
* - null output in symfony/console
* - null handler in a Chain of Responsiblities pattern
* - null command in a Command pattern
*
* Performance concerns : ok there is a call for nothing but we spare an "if is_null"
* I didn't run a benchmark but I think it's equivalent.
*/
class NullLogger implements LoggerInterface
{
public function log($str)
{
}
}

View File

@ -0,0 +1,20 @@
<?php
/*
* DesignPatternPHP
*/
namespace DesignPatterns\NullObject;
/**
* PrintLogger is a logger that prints the log entry to standard output
*/
class PrintLogger implements LoggerInterface
{
public function log($str)
{
echo $str;
}
}

30
NullObject/Service.php Normal file
View File

@ -0,0 +1,30 @@
<?php
/*
* DesignPatternPHP
*/
namespace DesignPatterns\NullObject;
/**
* Service is dummy service that uses a logger
*/
class Service
{
protected $logger;
// we inject the logger in ctor and it is mandatory
public function __construct(LoggerInterface $log)
{
$this->logger = $log;
}
public function doSomething()
{
// no more check "if (!is_null($this->logger))..." with the NullObject pattern
$this->logger->log('We are in ' . __METHOD__);
// something to do...
}
}

View File

@ -0,0 +1,35 @@
<?php
/*
* DesignPatternPHP
*/
namespace DesignPatterns\Tests\NullObject;
use DesignPatterns\NullObject\NullLogger;
use DesignPatterns\NullObject\Service;
use DesignPatterns\NullObject\PrintLogger;
/**
* LoggerTest tests for different loggers
*/
class LoggerTest extends \PHPUnit_Framework_TestCase
{
public function testNullObject()
{
// one can use a singleton for NullObjet : I don't think it's a good idea
// because the purpose behind null object is to "avoid special case".
$service = new Service(new NullLogger());
$this->expectOutputString(null); // no output
$service->doSomething();
}
public function testStandardLogger()
{
$service = new Service(new PrintLogger());
$this->expectOutputString('We are in DesignPatterns\NullObject\Service::doSomething');
$service->doSomething();
}
}