PHP控制反转(IOC)和依赖注入(DI)


Posted in PHP onMarch 13, 2017

先看一个例子:

<?php
class A
{
 public $b;
 public $c;
 public function A()
 {
  //TODO
 }
 public function Method()
 {
  $this->b=new B();
  $this->c=new C();
  $this->b->Method();
  $this->c->Method();
  //TODO
 }
}
class B
{
 public function B()
 {
  //TODO
 }
 public function Method()
 {
  //TODO
  echo 'b';
 }
}
class C
{
 public function C()
 {
  //TODO
 }
 public function Method()
 {
  //TODO
  echo 'c';
 }
}
$a=new A();
$a->Method();
?>

上面代码,我们很容易理解一句话:

A类依赖B类和C类

也就是说,如果今后开发过程中,要对B类或者C类修改,一旦涉及函数改名,函数参数数量变动,甚至整个类结构的调整,我们也要对A类做出相应的调整,A类的独立性丧失了,这在开发过程中是很不方便的,也就是我们说的“牵一发动全身”,如果两个类是两个人分别写的,矛盾往往就在这个时候产生了。。。

万一真的要改动B类和C类,有没有办法,可以不去改动或者尽量少改动A类的代码呢?这里要用到控制反转。

高层模块不应该依赖于底层模块,两个都应该依赖抽象。

控制反转(IOC)是一种思想,依赖注入(DI)是实施这种思想的方法。

第一种方法叫做:构造器注入(这种方法也不推荐用,但比不用要好)

class A
{
 public $b;
 public $c;
 public function A($b,$c)
 {
  $this->b=$b;
  $this->c=$c;
 }
 public function Method()
 {
  $this->b->Method();
  $this->c->Method();
 }
}

客户端类这样写:

$a=new A(new B(),new C());
$a->Method();

A类的构造器依赖B类和C类,通过构造器的参数传入,至少实现了一点,就是B类对象b和C类对象c的创建都移至了A类外,所以一旦B类和C类发生改动,A类无需做修改,只要在client类里改就可以了

假如有一天,我们需要扩充B类,做两个B类的子类

class B
{
 public function B()
 {
  //TODO
 }
 public function Method()
 {
  //TODO
  echo 'b';
 }
}
class B1 extends B
{
 public function B1()
 {
  //TODO
 }
 public function Method()
 {
  echo 'b1';
 }
}
class B2 extends B
{
 public function B2()
 {
  //TODO
 }
 public function Method()
 {
  echo 'b2';
 }
}

也很简单,客户端类这么写:

$a=new A(new B2(),new C());
$a->Method();

所以A类是不用关心B类到底有哪些个子类的,只要在客户端类关心就可以了。

第二种方法叫做:工厂模式注入(推荐使用)

class Factory
{
 public function Factory()
 {
  //TODO
 }
 public function create($s)
 {
  switch($s)
  {
   case 'B':
   {
    return new B();
    break;
   }
   case 'C':
   {
    return new C();
    break;
   }
   default:
   {
    return null;
    break;
   }
  }
 }
}

我们A类代码改为:

class A
{
 public $b;
 public $c;
 public function A()
 {
  //TODO
 }
 public function Method()
 {
  $f=new Factory();
  $this->b=$f->create('B');
  $this->c=$f->create('C');
  $this->b->Method();
  $this->c->Method();
  //TODO
 }
}

其实已经解耦了一小部分,至少如果B类和C类的构造函数要是发生变化,比如修改函数参数等,我们只需要改Factory类就可以了。

抽象不应该依赖于细节,细节应该依赖于抽象。

把B类和C类中的方法再抽象出来,做一个接口

interface IMethod
{
 public function Method();
}

这样,A类中的b变量和b变量和c变量就不再是一个具体的变量了,而是一个抽象类型的变量,不到运行那一刻,不知道他们的Method方式是怎么实现的。

class B implements IMethod
{
 public function B()
 {
  //TODO
 }
 public function Method()
 {
  //TODO
  echo 'b';
 }
}
class C implements IMethod
{
 public function C()
 {
  //TODO
 }
 public function Method()
 {
  //TODO
  echo 'c';
 }
}

总结几点:

1.我们把A类中的B类对象和C类对象的创建移至A类外

2.原本A类依赖B类和C类,现在变成了A依赖Factory,Factory依赖B和C。

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持三水点靠木!

PHP 相关文章推荐
关于PHP中操作MySQL数据库的一些要注意的问题
Oct 09 PHP
BBS(php &amp; mysql)完整版(五)
Oct 09 PHP
PHP新手上路(二)
Oct 09 PHP
URL Rewrite的设置方法
Jan 02 PHP
PHP弹出提示框并跳转到新页面即重定向到新页面
Jan 24 PHP
什么是PEAR?什么是PECL?PHP中两个容易混淆的概念解释
Jul 01 PHP
php轻量级的性能分析工具xhprof的安装使用
Aug 12 PHP
解析WordPress中函数钩子hook的作用及基本用法
Dec 22 PHP
PHP下载远程图片并保存到本地方法总结
Jan 22 PHP
php简单实现短网址(短链)还原的方法(测试可用)
May 09 PHP
PHP表单数据写入MySQL数据库的代码
May 31 PHP
php表单处理操作
Nov 16 PHP
ThinkPHP中类的构造函数_construct()与_initialize()的区别详解
Mar 13 #PHP
Thinkphp结合ajaxFileUpload实现异步图片传输示例
Mar 13 #PHP
php解析mht文件转换成html的实例
Mar 13 #PHP
使用phpQuery获取数组的实例
Mar 13 #PHP
php获取linux命令结果的实例
Mar 13 #PHP
老生常谈PHP位运算的用途
Mar 12 #PHP
PHP巧妙利用位运算实现网站权限管理的方法
Mar 12 #PHP
You might like
Discuz Uchome ajaxpost小技巧
2011/01/04 PHP
YII中assets的使用示例
2014/07/31 PHP
摘自织梦CMS的HTTP文件下载类
2015/08/08 PHP
PHP如何使用array_unshift()在数组开头插入元素
2020/09/01 PHP
Alliance vs Liquid BO3 第二场2.13
2021/03/10 DOTA
在Z-Blog中运行代码[html][/html](纯JS版)
2007/03/25 Javascript
jquery 得到当前页面高度和宽度的两个函数
2010/02/21 Javascript
一款Jquery 分页插件的改造方法(服务器端分页)
2011/07/11 Javascript
用dtree实现树形菜单 dtree使用说明
2011/10/17 Javascript
javascript 获取图片尺寸及放大图片
2013/09/04 Javascript
Javascript设计模式之观察者模式(推荐)
2016/03/29 Javascript
bootstrap日历插件datetimepicker使用方法
2016/12/14 Javascript
vue-resource调用promise取数据方式详解
2017/07/21 Javascript
Angular在模板驱动表单中自定义校验器的方法
2017/08/09 Javascript
浅谈Angular4实现热加载开发旅程
2017/09/08 Javascript
Angular实现点击按钮后在上方显示输入内容的方法
2017/12/27 Javascript
Vuejs在v-for中,利用index来对第一项添加class的方法
2018/03/03 Javascript
使用异步controller与jQuery实现卷帘式分页
2019/06/18 jQuery
vue中使用vee-validator完成表单校验方案
2019/11/01 Javascript
JS内置对象和Math对象知识点详解
2020/04/03 Javascript
[10:28]2018DOTA2国际邀请赛寻真——VGJ.S寻梦之路
2018/08/15 DOTA
[57:29]Alliance vs KG 2019国际邀请赛小组赛 BO2 第二场 8.16
2019/08/17 DOTA
在Python的框架中为MySQL实现restful接口的教程
2015/04/08 Python
Python基于回溯法子集树模板解决找零问题示例
2017/09/11 Python
PYQT5开启多个线程和窗口,多线程与多窗口的交互实例
2019/12/13 Python
Pycharm的Available Packages为空的解决方法
2020/09/18 Python
什么是Deployment descriptors;都有什么类型的部署描述符
2015/07/28 面试题
J2EE中的容器都包括哪些
2013/08/21 面试题
学校办公室主任职责
2013/12/27 职场文书
2014年公务员思想汇报范文:全心全意为人民服务
2014/03/06 职场文书
党员干部一句话承诺
2014/05/30 职场文书
公司应聘自荐书
2014/06/14 职场文书
我的中国梦心得体会范文
2016/01/05 职场文书
导游词之云南省玉龙雪山
2019/12/19 职场文书
MySQL 语句执行顺序举例解析
2022/06/05 MySQL
基于Android10渲染Surface的创建过程
2022/08/14 Java/Android