MVC 高度耦合解决方案
1. 实现 mvc 中的控制器对外部对象的二种依赖注入方式
- 问题阐述:简单的 MVC 内的模型实例化和视图实例化都是在控制器类实现的,这会导致许多问题。 1.这会导致控制器类严重依赖 Model 模型类和 View 视图类,2.这个模型类和视图类的构造方式一旦发生变化将会直接影响模型和视图的实例化过程,会导致控制器的类不能够独立于模型类和视图类,3.控制器类严重依赖模型类和视图类,这种现象就造成了代码之间的耦合度过高(联系过于紧密)。
//普通的MVC类
class Controller1
{
public function index()
{
// 1. 获取数据
$model = new Model;
$data = $model->getData();
// 2. 渲染模板/视图
$view = new View;
return $view->fetch($data);
}
}
- 解决方案:使用依赖注入的方式解决问题
1.1 以参数方式注入控制器类
- 比较好的解决方案是将模型类和视图类的实例化过程放到控制器的外面,然后把模型和视图的对象以参数的方式注入到控制器中,这就是依赖注入的思想。依赖注入的本意就是将当前类所依赖的其它类的实例以方法参数的形式注入到当前类中,依赖注入是实现代码中实现解耦的重要手段
实现依赖注入,那就必须把模型类和视图类移出控制器类外面。
//把外部对象实例化过程移到客户端处理,并以参数方式注入控制器类中
class Controller2
{
//需要约束参数的类型(对象和数组作为参数是允许在参数前面加类型约束的)
public function index(Model $model, View $view)
{
// 1. 获取数据
$data = $model->getData();
// 2. 渲染模板/视图
return $view->fetch($data);
}
public function index2(Model $model, View $view)
{
}
}
// 客户端
$model = new Model;
$view = new View;
// 实例化控制器类
$controller = new Controller2;
echo $controller->index($model, $view);
1.2 将要注入的参数放到构造方法中
- 聪明的小伙伴们应该注意到一点,刚才我们把外部依赖类的对象实例化过程,以参数的方式注入到了控制器类的普通方法 index 中,那为什么不可以注入到一个构造方法呢?在构造方法中初始化的参数或者属性可以在当前类中的所有方法中共享。
class Controller3
{
// 依赖对象属性
private $model;
private $view;
// 构造方法
public function __construct(Model $model, View $view)
{
// $model = new Model;
// $data = $model->getData();
$this->model = $model;
$this->view = $view;
}
public function index()
{
// 1. 获取数据
$data = $this->model->getData();
// 2. 渲染模板/视图
return $this->view->fetch($data);
}
public function index2()
{
// 1. 获取数据
$data = $this->model->getData();
// 2. 渲染模板/视图
return $this->view->fetch($data);
}
}
// 客户端
$model = new Model;
$view = new View;
// 实例化控制器类
$controller = new Controller3($model, $view);
echo $controller->index();
如果你还不了解构造方法,那在这里说明一下:构造方法也就是函数或类的初始化,也称为赋值过程。
2. 总结
实现了对象的共享,实际上这也不完美。实际上还有更好的方法—–服务容器,服务容器被很多大型 PHP 框架推崇,所有类的实例化过程都用服务容器进行管理。服务容器即管理所有对象,也管理着对象之间的依赖关系。