我正在玩一些设计模式,并想使用 SPL 的观察者模式创建一个示例。因为让观察者和主题完全通用是没有意义的,所以我想扩展接口以使它们更具体地用于手头的应用程序。问题是,当我运行下面的代码时,我收到诸如“DataAccess::update() 必须与 SplObserver::update() 兼容”之类的错误。
我知道我可以通过切换方法签名以匹配接口的签名来使此代码无错误地执行。我的问题是:为什么它不允许签名中定义的类的孩子? 下面,ModelObserver 是一个 SplObserver,Model 是一个 SplSubject。我原以为这会奏效。我错过了什么吗?
仅供参考,我知道我可以使用接口中定义的显式方法签名,并在我的代码逻辑中使用 instanceof 关键字来实现相同的目的。我只是希望找到一个更优雅的解决方案。谢谢!
<?php
interface ModelObserver extends SplObserver {
}
class DataAccess implements ModelObserver {
/*
* (non-PHPdoc) @see SplObserver::update()
*/
public function update(Model $subject) {
// TODO Auto-generated method stub
}
}
// Just a generic model for the example
class Model implements SplSubject {
private $_properties = array ();
private $_observers = array ();
/*
* generically handle properties you wouldn't want to do it quite like this
* for a real world scenario
*/
public function __get($name) {
return $this->_properties [$name];
}
public function __set($name, $value) {
$this->_properties [$name] = $value;
}
public function __call($method, $args) {
if (strpos ( $method, 'get' ) === 0) {
$name = lcfirst ( str_replace ( 'get', '', $method ) );
return $this->_properties [$name];
}
if (strpos ( $method, 'set' ) === 0) {
$name = lcfirst ( str_replace ( 'set', '', $method ) );
$this->_properties [$name] = $args [0];
return $this;
}
}
public function __toString() {
return print_r ( $this, true );
}
/*
* (non-PHPdoc) @see SplSubject::attach()
*/
public function attach(ModelObserver $observer) {
$this->_observers [] = $observer;
return $this;
}
/*
* (non-PHPdoc) @see SplSubject::detach()
*/
public function detach(ModelObserver $observer) {
if (in_array ( $observer, $this->_observers )) {
$f = function ($value) {
if ($value != $observer) {
return $value;
}
};
$observers = array_map ( $f, $this->_observers );
}
return $this;
}
/*
* (non-PHPdoc) @see SplSubject::notify()
*/
public function notify() {
foreach ($this->_observers as $observer) {
$observer->update($this);
}
}
}
$da = new DataAccess();
$model = new Model ();
$model->setName ( 'Joshua Kaiser' )->setAge ( 32 )->setOccupation ( 'Software Engineer' )
->attach($da);
echo $model;