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

时间:2014-08-08 18:01:52

标签: php oop interface observer-pattern method-signature

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

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

  • WeatherData类是Subject
  • CurrentConditionDisplayStatisticsDisplay是观察员

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

  

CurrentConditionDisplay :: update()声明必须兼容   使用ObserverInterface :: update()

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

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

是否有任何解决方案,而不是update(SubjectInterface $subject)中的ObserverInterface

这是我的代码:

接口

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;
    }
}

2 个答案:

答案 0 :(得分:1)

这只是您发布的代码的补充:您正在以某种方式错误地实现Observer / Subject模式。

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
    }
}

然后,在你的观察者中,你应该收到主题

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

这意味着两件事:

  1. 您的主题并不需要知道观察者的数量和类型。它只知道它有一些,它需要在它以某种方式改变其状态时通知它们。
  2. 每个观察者都需要决定它是否应该运行并对状态变化作出反应 - 或者不是。
  3. 总的来说,我建议reading a bit more in detail关于这种模式。

答案 1 :(得分:0)

嗯,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 )