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 相关文章推荐
动易数据转成dedecms的php程序
Apr 07 PHP
PHP开源开发框架ZendFramework使用中常见问题说明及解决方案
Jun 12 PHP
ThinkPHP单字母函数(快捷方法)使用总结
Jul 23 PHP
php的sso单点登录实现方法
Jan 08 PHP
PHP使用Redis替代文件存储Session的方法
Feb 15 PHP
详谈配置phpstorm完美支持Codeigniter(CI)代码自动完成(代码提示)
Apr 07 PHP
php 算法之实现相对路径的实例
Oct 17 PHP
实例讲解PHP页面静态化
Feb 05 PHP
PHP+MySQL使用mysql_num_rows实现模糊查询图书信息功能
May 31 PHP
PHP+Ajax简单get验证操作示例
Mar 02 PHP
PHP CURL中传递cookie的方法步骤
May 09 PHP
PHP实现简单日历类编写
Aug 28 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
全文搜索和替换
2006/10/09 PHP
一个简单的php实现的MySQL数据浏览器
2007/03/11 PHP
PHP开发中常用的8个小技巧
2008/08/27 PHP
建站常用13种PHP开源CMS比较
2009/08/23 PHP
PHP保留两位小数并且四舍五入及不四舍五入的方法
2013/09/22 PHP
php自定义函数实现JS的escape的方法示例
2016/07/07 PHP
AJAX的使用方法详解
2017/04/29 PHP
详解Yii2 之 生成 URL 的方法
2017/06/16 PHP
PHP实现支持CURL字符串证书传输的方法
2019/03/23 PHP
学习ExtJS Panel常用方法
2009/10/07 Javascript
将函数的实际参数转换成数组的方法
2010/01/25 Javascript
深入理解JavaScript作用域和作用域链
2011/10/21 Javascript
JS中类或对象的定义说明
2014/03/10 Javascript
原生javascript模仿win8等待提示圆圈进度条
2014/04/24 Javascript
jQuery中animate用法实例分析
2015/03/09 Javascript
javascript遇到html5的一些表单属性
2015/07/05 Javascript
原生JS实现的放大镜效果实例代码
2016/10/15 Javascript
jQuery通过改变input的type属性实现密码显示隐藏切换功能
2017/02/08 Javascript
Node.js数据库操作之查询MySQL数据库(二)
2017/03/04 Javascript
vue学习教程之带你一步步详细解析vue-cli
2017/12/26 Javascript
vue 循环加载数据并获取第一条记录的方法
2018/09/26 Javascript
浅谈TypeScript 用 Webpack/ts-node 运行的配置记录
2019/10/11 Javascript
基于Vue.js+Nuxt开发自定义弹出层组件
2020/10/09 Javascript
[07:06]2018DOTA2国际邀请赛寻真——卫冕冠军Team Liquid
2018/08/10 DOTA
对Python新手编程过程中如何规避一些常见问题的建议
2015/04/01 Python
对numpy 数组和矩阵的乘法的进一步理解
2018/04/04 Python
Python3爬虫使用Fidder实现APP爬取示例
2018/11/27 Python
python 进程 进程池 进程间通信实现解析
2019/08/23 Python
简单易懂Pytorch实战实例VGG深度网络
2019/08/27 Python
Python中 Global和Nonlocal的用法详解
2020/01/20 Python
德国团购网站:Groupon德国
2018/03/13 全球购物
融资租赁计划书
2014/04/29 职场文书
项目申报专员岗位职责
2014/07/09 职场文书
导游词之岳阳楼
2019/09/25 职场文书
导游词之藏龙百瀑景区
2019/12/30 职场文书
Java中API的使用方法详情
2022/04/06 Java/Android