OO,MVC和Observer模式未按预期工作

时间:2015-02-13 16:02:54

标签: php oop model-view-controller observer-pattern

在我的课堂上,我们使用带有Java中的观察者模式的MVC创建了一个简单的应用程序,它可以工作。视图无法调用模型中未包含在(Observable)界面中的任何方法,反之亦然。

我非常喜欢PHP,并决定在PHP中使用相同(简化)的示例。我注意到即使我使用接口并将模型的引用作为接口传递,视图仍然可以在模型中调用每个方法,使整个模式无用。

有没有我忽略的东西,或者这在PHP中是不可能的?

PHP代码(每个引用,方法等与Java应用程序完全相同):

class App
{
    public function __construct()
    {
        $model = new Model();
        $controller = new Controller($model);
    }

}

class Model implements Observable
{
    private $view;
    private $count = 1;

    public function __construct()
    {
        echo 'Model created. <br>';
    }

    public function registrate(Observer $view)
    {
        $this->view = $view;
        echo 'Model: view is registered. <br>';
    }

    public function addOne()
    {
        $this->count += 1;
        $this->view->modelChanged($this);
    }

    public function getCounter()
    {
        return $this->count;
    }

    public function getMessage()
    {
        return 'The view should not be able to call this method.';
    }

}

class Controller
{
    private $view;
    private $model;

    public function __construct(Model $model)
    {
        echo 'Controller created. <br>';
        $this->model = $model;
        $this->view = new View($this->model);
        $this->model->addOne();
    }

}

class View implements Observer
{
    public function __construct(Observable $model)
    {
        echo 'View created. <br>';
        $model->registrate($this);
    }

    public function modelChanged(Observable $model)
    {
        // Should only be able to call method "getCounter()"
        echo $model->getMessage();
    }

}

interface Observable
{
    public function registrate(Observer $view);
    public function getCounter();
}

interface Observer
{
    public function modelChanged(Observable $model);
}

输出,如果你运行它是:

  

模型已创建。

     

创建控制器。

     

查看已创建。

     

模型:视图已注册。

视图不应该能够调用此方法。如您所见,视图可以调用在Observable接口内声明的 not 模型的方法。

这怎么可能?为什么这不像在Java中那样在PHP中起作用?

1 个答案:

答案 0 :(得分:1)

当然,视图可以调用您在模型上定义的每个方法:所有方法都是 public ,这意味着它们可以从任何地方调用。只需将它们定义为protectedprivate而不是......

当然,这会限制您在其他组件(例如控制器)中使用该模型的方式。要解决这个问题,一个简单的解决方法是创建一个包装器,当您将模型传递给视图时,可以将其包裹起来:

class View implements Observable
{
    public function __construct(ViewObservable $model)
    {
        //do stuff here
    }
}
//Wrapper:
class ViewObservable
{
    /**
     * @var Model
     */
    protected $payload = null;
    public class __construct(Observable $model)
    {
        $this->payload = $model;
    }
    public function getCounter()
    {
        return $this->payload->getCounter();
    }
}

但实际上,你可能想重新考虑一件事情或者2.使用接口是好的,但是对于所有组件来说,(至少对我来说)没有多大意义。 MVC架构实现相同的接口。所有组件都有不同的工作要执行,因此应具有不同的接口要求。