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,这意味着它们可以从任何地方调用。只需将它们定义为 protected
或 private
而不是...
当然,这会限制您在其他组件(例如控制器)中使用该模型的方式。要解决该问题,一个简单的解决方法是创建一个包装器,您可以在将模型传递给视图时将其包装起来:
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 架构中的组件实现相同的接口。所有组件都有不同的工作要执行,因此应该有不同的接口要求。
在我的 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,这意味着它们可以从任何地方调用。只需将它们定义为 protected
或 private
而不是...
当然,这会限制您在其他组件(例如控制器)中使用该模型的方式。要解决该问题,一个简单的解决方法是创建一个包装器,您可以在将模型传递给视图时将其包装起来:
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 架构中的组件实现相同的接口。所有组件都有不同的工作要执行,因此应该有不同的接口要求。