接口中接受两个整数的方法


PHP - Method in interface that accepts two integers

我试图理解观察者模式。到目前为止一切都很顺利,我知道事情是如何运作的。

但是我有一个问题。在Head First: Design Patterns书中,有一个气象站程序的例子。

  • WeatherData类为Subject
  • CurrentConditionDisplayStatisticsDisplay为观察者

我已经实现了所有需要的代码。但是我总是得到这个错误:

CurrentConditionDisplay::update()的声明必须兼容ObserverInterface::更新()

现在我知道导致这个错误的原因是接口中的update()方法与在参数方面实现它的具体类不同。

但在CurrentConditionDisplay类我有update($temp, $humidity)在接口我有update()。我的意思是如何在一个类中指定update()方法需要两个参数(温度和湿度),而在另一个类中需要(温度和压力)?

是否有任何解决方案,而不是在ObserverInterfaceupdate(SubjectInterface $subject) ?

下面是我的代码:

接口:

interface SubjectInterface
{
    public function registerSubscriber(ObserverInterface $observerInterface);
    public function removeSubscriber(ObserverInterface $observerInterface);
    public function notifySubscriber();
}
interface ObserverInterface
{
    public function update();
}
interface DisplayInterface
{
    public function display();
}

* *类:* *

WeatherData

class WeatherData implements SubjectInterface
{
    /**
     * @var array
     */
    protected $observers = [];
    protected $temp;
    protected $humidity;
    protected $pressure;
    public function registerSubscriber(ObserverInterface $observer)
    {
        $this->observers[] = $observer;
    }
    public function removeSubscriber(ObserverInterface $observer)
    {
        $i = array_search($this->observers, $observer);
        if ($i) {
            unset($this->observers[$i]);
        }
    }
    public function notifySubscriber()
    {
        foreach ($this->observers as $observer) {
            /** @var $observer ObserverInterface */
            $observer->update();
        }
    }
    public function setValues($temp, $humidity, $pressure)
    {
        $this->temp = $temp;
        $this->humidity = $humidity;
        $this->pressure = $pressure;
        $this->notifySubscriber();
    }
}

CurrentConditionDisplay

class CurrentConditionDisplay implements ObserverInterface, DisplayInterface
{
    protected $temp;
    protected $humidity;
    public function __construct(SubjectInterface $subject) {
        $subject->registerSubscriber($this);
    }
    public function display()
    {
        if(isset($this->temp) && isset($this->humidity)) {
            echo sprintf("CURRENT:<br>Temp: %d, Humidity: %d <br>", $this->temp, $this->humidity);
        }
    }
    public function update($new_temp, $new_humidity)
    {
        $this->temp = $new_temp;
        $this->humidity = $new_humidity;
        $this->display();
    }
}

StatisticDisplay

class StatisticDisplay implements ObserverInterface, DisplayInterface
{
    protected $temp;
    protected $pressure;
    public function __construct(SubjectInterface $subject) {
        $subject->registerSubscriber($this);
    }
    public function display()
    {
        if(isset($this->temp) && isset($this->pressure)) {
            return sprintf("STATISTIC:<br>Ration: %d <br>", $this->temp / $this->pressure);
        }
    }
    public function update($new_temp, $new_pressure)
    {
        $this->temp = $new_temp;
        $this->humidity = $new_pressure;
    }
}

这只是对你发布的代码的补充:你正在实现观察者/主题模式,不知怎么错了。

Subject::register()方法(WeatherData::registerSubscriber())应该用于实际向主题添加观察者。这应该发生在某种类型的控制器中,而不是在观察者本身。扪心自问:观察者如何向一个主体自我注册?这个不能工作:

public function __construct( SubjectInterface $subject ) {
    $subject->registerSubscriber($this);
}

应该是将自己传递给观察者的主体。换句话说:你的实际主体(由观察者监控),通知每个观察者。

// This class `implements SubjectInterface` */
public function notifySubscriber()
{
    foreach ($this->observers as $observer) {
        /** @var $observer ObserverInterface */
        $observer->update( $this ); // HERE WE HAND OVER THE SUBJECT TO THE OBSERVER
    }
}

然后,在Observer中,你应该接收到Subject

public function update( Subjectinterface $subject )
{
    if ( "bar" === $this->foo() )
        // do something if the Subject has the desired state
}

意味着两件事:

  1. 你的受试者不需要知道观察者的数量和类型。它只知道它得到了一些,当它以某种方式改变它的状态时,它需要通知它们。
  2. 每个观察者都需要决定它是否应该运行并对状态变化做出反应。

总的来说,我建议阅读更多关于这个模式的细节。

那么,你在CurrentConditionDisplay::update()中的方法是这个

public function update($new_temp, $new_humidity)

当你在implement执行ObserverInterface::update()方法时,它应该看起来像这样:

public function update();

当PHP告诉你

CurrentConditionDisplay::update()的声明必须与ObserverInterface::update()兼容

那么它告诉你你的方法必须匹配-在名称,可访问性(public|protected|private)和参数。

所以你的接口需要有一个不同的方法如果你想让它的实现类有参数:

public function update( $new_temp, $new_humidity )