php教程:php设计模式介绍之观测模式(3)

http://www.itjxue.com  2015-07-17 08:20  来源:未知  点击次数: 

有了合适而正确的观测者,我们就可以在观测模式下,从函数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()就更加合适,因为这两个名字更加贴近这个函数的功能。

(责任编辑:IT教学网)

更多