有了合适而正确的观测者,我们就可以在观测模式下,从函数attach()开始继续测试ErrorHandler类。
class Observer { function update() { die(‘abstract method’); } } Mock::Generate(‘Observer’);
class ErrorHandlerTestCase extends UnitTestCase { function TestAttach() { $eh =& new ErrorHandler; $observer =& new MockObserver($this); $observer->expectOnce( ‘update’ ,array(‘*’)); // array(&$eh)
$eh->attach($observer); $eh->notify(); $observer->tally();
} function TestDetach() { /* ... */ } }
在这次测试中,一个简单的观测类被创建出来,作为所有观测者的接口。为了测试函数attach(),一个基于这个观测类的伪模式被创建出来,并且和ErrorHandler测试实例关联在一起。然后,当公共函数notify()被调用时,伪模式将证实update()函数曾经被调用过。
请注意刚才提及的的在模拟观测中所创建的函数array(&$eh)中的参数。在理想状态中,那个测试应该可以通过的。然而,由于PHP语言的限制,这将产生一个致命错误:“Nesting Level Too Deep――循环依赖?”。为了避免出现那样的问题,代码中必须使用简单测试下“Wild Card”功能,以便允许所有参数都能像预期的那样传递。
? Nesting Level Too Deep
因为ErrorHandler在数组$_observer中包含涉及到模拟观测的参数,本来预期是要将它传递给模拟观测的。所以,PHP产生一个“Nesting Level Too Deep”错误。而循环依赖就像一个初级的PHP问题,甚至可以在一个简单的PHP环境中发现它。(请参考http://bugs.php.net/bug.php?id=31449.)
ErrorHandler开始应该像下面这样构造:
class ErrorHandler { var $_observers=array(); function attach(&$observer) { $this->_observers[] =& $observer; }
function notify() { foreach(array_keys($this->_observers) as $key) { $observer =& $this->_observers[$key]; $observer->update($this); } }
根据上面的代码,你必须在每一个具体的观测者中添加一个update()函数。在每个实例中,update()函数需要知道如何从被观测者ErrorHandler类中获取信息,进而执行自身的相应功能。这里是添加的代码。
class FileErrorLogger { var $_fh; function FileErrorLogger($file_handle) { $this->_fh = $file_handle; } function write($msg) { fwrite($this->_fh, date(‘Y-m-d H:i:s: ‘).$msg); } function update(&$error_handler) { $error = $error_handler->getState(); $this->write($error[‘msg’]); } }
class EmailErrorLogger { var $_addr; var $_subject; function EmailErrorLogger($addr, $subject=’Application Error Message’) { $this->_addr = $addr; $this->_subject = $subject; } function mail($msg) { mail($this->_addr ,$this->_subject ,date(‘Y-m-d H:i:s: ‘).$msg); } function update(&$error_handler) { $error = $error_handler->getState(); $this->mail($error[‘msg’]); } }
上面两个update()函数中的每一个,都需要将ErrorHandler作为参数,以便从中获得错误信息,然后调用一个内部函数,来处理这个错误。每个update()函数通过ErrorHandler中的getState()函数来获取信息。那个函数以getState()命名是为了在GoF模式中,保持模式的整体和谐性。但是,如果将这个函数命名为getError()或者getErrorInfo()就更加合适,因为这两个名字更加贴近这个函数的功能。
出处:phpchina
责任编辑:bluehearts
上一页 php设计模式介绍之观测模式 [2] 下一页 php设计模式介绍之观测模式 [4]
◎进入论坛网络编程版块参加讨论
|