gpt4 book ai didi

php - 如何实现扩展接口(interface)?

转载 作者:搜寻专家 更新时间:2023-10-31 20:45:58 24 4
gpt4 key购买 nike

我正在研究一些设计模式,想创建一个使用 SPL 观察者模式的示例。因为让观察者和主题完全通用是没有意义的,所以我想扩展接口(interface)以使它们更具体地针对手头的应用程序。问题是,当我运行下面的代码时,出现类似“DataAccess::update() 必须与 SplObserver::update() 兼容”的错误。

我知道我可以通过切换方法签名以匹配接口(interface)的方法签名来使这段代码无错误地执行。我的问题是:为什么不允许签名中定义的类的子类? 下面,ModelObserver 是一个 SplObserver,而 Model 是一个 SplSubject。我原以为这会奏效。我错过了什么吗?

仅供引用,我知道我可以使用接口(interface)中定义的显式方法签名并在我的代码逻辑中使用 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;

最佳答案

限制 DataAccess::update() 接受您的子 Model 会破坏此接口(interface)的契约。

是的,所有 Model 对象都属于 SplSubject 类,但并非所有 SplSubject 都属于 Model 类。接口(interface)是保证其实现类支持接口(interface)支持的所有内容的契约。

您的代码(如果有效)会将 DataAccess::update() 方法仅限于 Model 子类,而不是更广泛的父类 SplSubjects 。您不能缩小传递给接口(interface)定义的方法的参数的范围。

假设您向模型类添加了属性 public $foo。如果允许,您可以在 DataAccess::update() 方法中使用该属性 $foo。有人可能会出现并将 SplSubjects 扩展到一个没有 $foo 属性的子 OddModel。他们无法再将 OddModel 传递到您的 DataAccess::update() 函数中——如果他们可以的话,它会因为没有 $foo 属性而中断存在于 OddModel

这是接口(interface)背后的全部思想,通过实现它们,您同意 100% 支持接口(interface)定义的内容。在这种情况下,您的界面显示:

if you implement me, you must accept every SplSubject or class that extends SplSubject

你正在实现接口(interface)试图破坏契约。

关于php - 如何实现扩展接口(interface)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13313175/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com