我正在玩一些設計模式,並希望使用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;
感謝您的反饋意見。在這種情況下,似乎有意義的是,可能需要縮小要傳遞參數的範圍,因爲並非所有SplObserver對象都必須適用於處理模型。如果我不能通過繼承來縮小接口的範圍,我能想到的下一個最好的事情是在方法本身內部測試SplObserver和SplSubject的實例,並在它不是兼容的觀察者或主題時拋出異常。你會同意嗎,還是我錯過了什麼? –
...而不是重新定義方法,您可以簡單地在'DataAccess'中添加一個檢查。例如:'if(!$ subject instanceOf Model)拋出新的DataAccessException('不是有效的模型主題');'或類似的東西。 –
@JoshuaKaiser在你實現的方法裏面你可以做任何你想做的事情,但是整個想法是完全支持這個接口。你應該問爲什麼你要實現一個接口,它不能完全滿足接口定義所要求的所有事情。界面是一個承諾。如果你不能遵守承諾,請不要使用界面。如何不能所有的SplObserver處理模型?模型的類型是SplSubject - 它們可能無法很好地處理,在這種情況下,肯定會拋出異常 – Ray