OO、MVC 和观察者模式未按预期工作

OO, MVC and Observer pattern not working as expected

在我的 class 中,我们在 Java 中使用 MVC 和观察者模式制作了一个简单的应用程序并且它有效。视图不能调用模型中未包含在 (Observable) 接口中的任何方法,反之亦然。

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

我是否忽略了什么,或者这在 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);
}

输出,如果你运行这是:

Model created.

Controller created.

View created.

Model: view is registered.

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

这怎么可能?为什么这在 PHP 中不像在 Java 中那样有效?

当然,视图可以调用您在模型上定义的每个方法:所有方法都是 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();
    }
}

但实际上,您可能想要重新考虑一件事或两件事。使用接口很好,但拥有 all[= 没有多大意义(至少对我而言) 22=] MVC 架构中的组件实现相同的接口。所有组件都有不同的工作要执行,因此应该有不同的接口要求。