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 相关文章推荐
4.与数据库的连接
Oct 09 PHP
PHP中for循环语句的几种变型
Mar 16 PHP
全局记录程序片段的运行时间 正确找到程序逻辑耗时多的断点
Jan 06 PHP
浅析PHP中call user func()函数及如何使用call user func调用自定义函数
Nov 05 PHP
PHP自定义函数实现格式化秒的方法
Sep 14 PHP
PHP中仿制 ecshop验证码实例
Jan 06 PHP
Yii2 hasOne(), hasMany() 实现三表关联的方法(两种)
Feb 15 PHP
php利用ffmpeg提取视频中音频与视频画面的方法详解
Jun 07 PHP
thinkPHP5框架auth权限控制类与用法示例
Jun 12 PHP
Thinkphp5 自定义上传文件名的实现方法
Jul 23 PHP
phpstudy后门rce批量利用脚本的实现
Dec 12 PHP
PHP 使用位运算实现四则运算的代码
Mar 09 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
php Undefined index的问题
2009/06/01 PHP
CI框架无限级分类+递归的实现代码
2016/11/01 PHP
PHP文件操作实例总结【文件上传、下载、分页】
2018/12/08 PHP
PHP的垃圾回收机制代码实例讲解
2021/02/27 PHP
jQuery的.live()和.die() 使用介绍
2011/09/10 Javascript
CSS鼠标响应事件经过、移动、点击示例介绍
2013/09/04 Javascript
Dojo Javascript 编程规范 规范自己的JavaScript书写
2014/10/26 Javascript
JavaScript实现鼠标滑过处生成气泡的方法
2015/05/16 Javascript
JQuery中两个ul标签的li互相移动实现方法
2015/05/18 Javascript
js实现类似MSN提示的页面效果代码分享
2015/08/24 Javascript
使用JavaScript实现一个小程序之99乘法表
2017/09/21 Javascript
Vue 实现列表动态添加和删除的两种方法小结
2018/09/07 Javascript
小程序兼容安卓和IOS数据处理问题及坑
2018/09/18 Javascript
javascript 关于赋值、浅拷贝、深拷贝的个人理解
2019/11/01 Javascript
微信小程序纯文本实现@功能
2020/04/08 Javascript
vue项目中使用bpmn-自定义platter的示例代码
2020/05/11 Javascript
[04:42]2015国际邀请赛CDEC战队晋级之路
2015/08/13 DOTA
Python使用MYSQLDB实现从数据库中导出XML文件的方法
2015/05/11 Python
详解Django中的权限和组以及消息
2015/07/23 Python
Python基于分水岭算法解决走迷宫游戏示例
2017/09/26 Python
NumPy统计函数的实现方法
2020/01/21 Python
Python对Tornado请求与响应的数据处理
2020/02/12 Python
python实现滑雪者小游戏
2020/02/22 Python
三年大学自我鉴定
2014/01/16 职场文书
实习生求职自荐信
2014/02/07 职场文书
士力架广告词
2014/03/20 职场文书
经典演讲稿汇总
2014/05/19 职场文书
公司门卫岗位职责范本
2014/07/08 职场文书
绿色小区申报材料
2014/08/22 职场文书
2014办公室副主任四风对照检查材料思想汇报
2014/09/20 职场文书
工人先锋号申报材料
2014/12/29 职场文书
三八妇女节寄语
2015/02/27 职场文书
2015年城市管理工作总结
2015/05/23 职场文书
读《瓦尔登湖》有感:每个人都需要一个瓦尔登湖
2019/10/17 职场文书
Django+Celery实现定时任务的示例
2021/06/23 Python
Java数据结构之堆(优先队列)
2022/05/20 Java/Android