空对象模式 目的 空对象模式 并不是 GoF 23 种经典设计模式之一,但它是一种(在软件开发中)经常用到的设计模式,以至于可单独作为一种设计模式存在。
空对象模式有以下优点:
简化客户端代码
减少抛出空指针异常的几率
需要更少的测试用例
在该模式中,一个返回对象或 null 的方法,应该相应地返回那个业务对象或 NullObject。NullObject 通过消除客户端代码中的条件检查达到简化代码的目的,例如:
1 2 3 4 5 6 7 if (!is_null ($obj )) { $obj ->callSomething (); } $obj ->callSomething ();
使用场景
空日志记录器或空输出对象,在需要保留对象之间的标准交互方式时(即使什么也不做)
在职责链模式 中使用 null 处理程序时
在命令模式 中使用 null 命令时
UML 类图
代码 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 \Extend \NullObject ;class Service { private Logger $logger ; public function __construct (Logger $logger ) { $this ->logger = $logger ; } public function doSomething ( ) { $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 \Extend \NullObject ;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 \Extend \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 \Extend \NullObject ;class NullLogger implements Logger { public function log (string $str ) { } }
测试 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 \Extend \NullObject \Tests ;use DesignPatterns \Extend \NullObject \NullLogger ;use DesignPatterns \Extend \NullObject \PrintLogger ;use DesignPatterns \Extend \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\Extend\NullObject\Service::doSomething' ); $service ->doSomething (); } }