《PHP设计模式介绍》第九章 观测模式(2)_PHP教程
推荐:《PHP设计模式介绍》第八章 迭代器模式类中的面向对象编程封装应用逻辑。类,就是实例化的对象,每个单独的对象都有一个特定的身份和状态。单独的对象是一种组织代码的有用方法,但通常你会处理一组对象或者集合。 属性来自 SQL 查
ErrorHandler开始应该像下面这样构造:
classErrorHandler{
var$_observers=array();
functionattach(&$observer){
$this->_observers[]=&$observer;
}
functionnotify(){
foreach(array_keys($this->_observers)as$key){
$observer=&$this->_observers[$key];
$observer->update($this);
}
}
根据上面的代码,你必须在每一个具体的观测者中添加一个update()函数。在每个实例中,update()函数需要知道如何从被观测者ErrorHandler类中获取信息,进而执行自身的相应功能。这里是添加的代码。
classFileErrorLogger{
var$_fh;
functionFileErrorLogger($file_handle){
$this->_fh=$file_handle;
}
functionwrite($msg){
fwrite($this->_fh,date(‘Y-m-dH:i:s:‘).$msg);
}
functionupdate(&$error_handler){
$error=$error_handler->getState();
$this->write($error[‘msg’]);
}
}
classEmailErrorLogger{
var$_addr;
var$_subject;
functionEmailErrorLogger($addr,
$subject=’ApplicationErrorMessage’){
$this->_addr=$addr;
$this->_subject=$subject;
}
functionmail($msg){
mail($this->_addr
,$this->_subject
,date(‘Y-m-dH:i:s:‘).$msg);
}
functionupdate(&$error_handler){
$error=$error_handler->getState();
$this->mail($error[‘msg’]);
}
}
另外,如果你不喜欢该模式下对象与对象之间的连接方式,你可以更改update()函数让它来发送一个信息(类似于本例中的错误信息数组或者几个信息对象)来避免引用自己。
这里是一个全新的ErrorHandler,不仅做了最新的修改并且还包含detach()函数:
classErrorHandler{
var$_observers=array();
var$_error_info;
functionattach(&$observer){
$this->_observers[]=&$observer;
}
functiondetach(&$observer){
foreach(array_keys($this->_observers)as$key){
if($this->_observers[$key]===$observer){
unset($this->_observers[$key]);
return;
}
}
}
functionnotify(){
foreach(array_keys($this->_observers)as$key){
$observer=&$this->_observers[$key];
$observer->update($this);
}
}
functiongetState(){
return$this->_error_info;
}
functionsetState($info){
$this->_error_info=$info;
$this->notify();
}
}
你现在已经拥有了观测模式下的一个完整工具。
现在,回到本章的原始目标中,让我们看看如何在一个真正的PHP脚本中应用ErrorHandler。为了在一个PHP应用中包含观测者,你必须实例化ErrorHandler类,并确认函数set_error_handler()使用完全相同的参数。这听起来就像最近的一个问题:单件模式。
让我们作一个Factory()函数,它是一个简单的PHP函数,可以返回ErrorHandler的单态实例。
function&getErrorHandlerInstance(){
static$instance=array();
if(!$instance)$instance[0]=&newErrorHandler();
return$instance[0];
}
现在,让我们写一个错误记录句柄功能来获取单态ErrorHandler,改变它的状态来反映错误,并且通知“观测者”。
functionobserver_error_handler(
$errno,$errstr,$errfile,$errline,$errcontext){
$eh=&getErrorHandlerInstance();
$eh->setState(array(
‘number’=>$errno
,’msg’=>$errstr
,’file’=>$errfile
,’line’=>$errline
,’context’=>$errcontext
));
}
也许你会注意到这里并没有ErrorHandler::notify()函数。为什么呢?因为ErrorHandler不论何时,只要状态一改变就会自动发出通知。
classErrorHandler{
//...
functionsetState($info){
$this->_error_info=$info;
$this->notify();
}
}
这种“默认通知”的方法,有利有弊。但先进之处在于客户端代码不需要包含通知的触发代码。
当然,如果主体对象的状态有好几处变化,所有的变动都对应不同的函数,你就可以选择让客体代码强制调用notify()函数。
自从你能正确使用这些辅助工具后,你给ErrorHandler添加的另一种类型的记录方式就会变得相当的容易?你现在只需要拥有向系统中写日志的权限。稍微查一下PHP手册(http://www.php.net/syslog),你就可以找到一些非常有用的函数来建立日志系统。这些可以很容易的被封装到一个新的类里,以便和ErrorHandler联合使用。
classSyslogErrorLogger{
functionSyslogErrorLogger($msg){define_syslog_variables();openlog($msg,LOG_ODELAY,LOG_USER);
}
functionlog($msg){
syslog(LOG_WARNING,$msg);
}
functionupdate(&$error_handler){
$error=$error_handler->getState();
$this->log($error[‘msg’]);
}
}
注:错误日志的用处
日志是非常有用的――如果有人使用它们的话。但是,如果没有人使用日志,那么记录日志的代码就是一堆无用的代码
如果想知道更详细的评价,请查看
http://www.lastcraft.com/blog/index.php?p=4
结论
观测模式是非常有用的。这里的例子是完全静态的--观测者可以在脚本的初始化阶段被配置且被生成。要想展示观测模式的灵活性,最好是在一个更加动态的应用中--你需要根据脚本中的其他事情来添加或删除观测者。以常见的“生存时间”或者说该PHP脚本的允许执行时间打个比方,当同一个脚本在不同的情况下执行时,就可以根据不同的观测者分别配置,而不需要动态改变一个脚本的流程。这就和通过延长脚本执行时间的PHP-GTK库有很大不同。
分享:《PHP设计模式介绍》第七章 策略模式在编写面向对象的代码的时,有些时候你需要一个能够自己根据不同的条件来引入不同的操作对象实例。例如,一个菜单功能能够根据用户的“皮肤”首选项来决定是否采用水平的还是垂直的排
- 相关链接:
- 教程说明:
PHP教程-《PHP设计模式介绍》第九章 观测模式(2)。