这2个其实都算得上是一种设计模式或者说是一种软件设计思想,目的都是为了增加软件可维护性和扩展性,在很多框架,比如Java Web框架SpringMVC 和PHP Web框架laravel里面都有应用。

首先得理解什么叫依赖?从宏观上看,得益于开源软件运行的兴起,很多时候我们写项目并不是什么都是从零开始,我们往往会利用很多现成的开源代码进行快速开发,能不重复造轮子最好,所以我们往往依赖很多开源组件。gradle、npm、composer 等工具的部分功能就是解决项目依赖问题。

从微观上看,在实际写代码里面,对象与对象之间也会产生依赖关系,比如一个数据库查询类需要用到一个数据库连接、一个文章评论类用到一个文章,这里的依赖主要指对象之间的关系。

举个栗子,在一个 SessionService 里面你需要一个 FileSession :

普通写法:

class FileSession
{private $file;... more codepublic function set($name, $value){echo "set $name = $value into $this->file\n";}public function get($name){echo "get $name value\n";}
}
复制代码

service类:

class SessionService
{private $sessionHandler;public function __construct(){$this->sessionHandler = new FileSession();}public function set($name, $value){$this->sessionHandler->set($name, $value);}public function get($name){return $this->sessionHandler->get($name);}...more code
}
复制代码

在这种普通写法里面,当我们需要一个 sessionHandler 的时候我们是直接在构造函数里面实例化,这样没啥问题,确实解决了依赖问题。但是依赖注入的另一个词“注入”更强调的是一种从外部而来的,而不是内部。

改造如下:

依赖注入写法:

class SessionService
{private $sessionHandler;public function __construct($sessionHandler){$this->sessionHandler = $sessionHandler;}public function set($name, $value){$this->sessionHandler->set($name, $value);}public function get($name){return $this->sessionHandler->get($name);}...more code
}
复制代码

这种写法要求你在使用service的时候从外部传入一个handler,这就实现了依赖注入,注入的方式有很多种,刚才这种可以称之为构造器注入,还有一种叫setter注入,比如说,我们可以在service里面里面提供一个setter函数用于设置所需的handler:

public function setSessionHandler($sessionHandler)
{$this->sessionHandler = $sessionHandler
}
复制代码

这种写法有哪些好处呢?一个是解耦,假如说这个FileSession实例化的时候还需要其它操作,比如传入一个配置参数,原本的写法可能就需要更改service类了,在构造函数里面啪啪啪写一堆。还有就是方便测试,既然解耦了就可以很方便的进行单元测试。另一个是控制反转,就是说这个FileSession外部传入的,是service类无法控制的,也就说控制权在于外部。

很多软件在设计的时候都采用分层结构,最典型的就是计算机网络,Http协议依赖TCP协议,层与层之间通过约定的的接口进行交互,既减少了代码的复杂度,也提高了可维护性。比如说你哪一天重构了FileSession,没问题,只要你保证所有方法的返回结果和之前一样就行。

为了更灵活的运用这种注入机制我们可能需要采用一个接口去约束,举个例子,我们先增加一个接口sessionHandler:

interface SessionHandler
{public function set($name, $value);public function get($name);
}
复制代码

我们约定,只要你实现了这个接口,你就可以当一个sessionHandler,你就可以用来处理session,至于你怎么实现,service不管,比如说我们换一个redis:

class RedisHandler implments SessionHandler
{private $redisInstance;public function __construct(){$this->redisInstance = new Redis();}public function set($name, $value){$this->redisInstance->set($name, $value);}public function get($name){return $this->redisInstance->get($name);}
}
复制代码

这时候我们可以在service的构造函数稍作修改,增加一个类型约束:

 public function __construct(SessionHandler $sessionHandler){$this->sessionHandler = $sessionHandler;}
复制代码

这样的设计之后,好处显而易见,我们可以很轻松替换掉之前的fileSession,不改动service的一行代码,只要按照sessionHandler的接口去实现相应的方法就行,在laravel里面这样的接口就叫做 Contracts,下面就是框架里面的Cache缓存的 Contracts:

<?phpnamespace Illuminate\Contracts\Cache;interface Store
{/*** Retrieve an item from the cache by key.** @param  string|array  $key* @return mixed*/public function get($key);/*** Retrieve multiple items from the cache by key.** Items not found in the cache will have a null value.** @param  array  $keys* @return array*/public function many(array $keys);/*** Store an item in the cache for a given number of minutes.** @param  string  $key* @param  mixed   $value* @param  float|int  $minutes* @return void*/public function put($key, $value, $minutes);/*** Store multiple items in the cache for a given number of minutes.** @param  array  $values* @param  float|int  $minutes* @return void*/public function putMany(array $values, $minutes);... more code
}
复制代码

据我看到的,在laravel框架里面自带了至少5种实现,分别是Array、File、Database、Memcached、Redis, 如果你愿意你也可以自己去实现这个 Contracts,然后替换到框架里面的,不过框架本身实现的已经非常优秀了,除非你写的更好,一般情况下不需要这样做,但是laravel提供了这种可能。 同样,在laravel框架里面session自带了Cache,Database,File这种几种实现,可以随意切换。


IOC容器

说了最后,必须再说说IOC容器,IOC核心思想是通过IoC容器管理对象的生成、资源获取、销毁等生命周期,在IoC容器中建立对象与对象之间的依赖关系,IoC容器启动后,所有对象直接取用,调用层不再使用new操作符产生对象和建立对象之间的依赖关系。

简单理解就是不再使用new创建对象了,而且使用容器来管理对象,需要对象就从容器里面取,而且你只需要在参数上声明依赖,容器就直接给你对象了,炒鸡方便,比如在laravel里面,有很多这样的写法:

public function comment(Post $post, Request $request)
{$this->validate($request, ['content' => 'required|min:5']);$comment = new Comment(['content' => $request->get('content'),'user_id' => auth()->user()->id,'post_id' => $post->id,]);$post->comments()->save($comment);return redirect()->back();
}
复制代码

我们只需要在方法的参数上面标明所需的方法,就可以在代码直接用了,ioc容器替我们自动注入了依赖!

PHP依赖注入(DI)和控制反转(IOC)相关推荐

  1. PHP依赖注入(DI)和控制反转(IoC)详解

    这篇文章主要介绍了PHP依赖注入(DI)和控制反转(IoC)的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下 首先依赖注入和控制反转说的是同一个东西,是一种设计模式,这种设计模式用来减少程 ...

  2. 代码的演化-DI(理解依赖注入di,控制反转ioc)

    控制反转(Inversion of Control IoC)在java中,Spring就是一个很好的应用.用于解除使用者和生产者的耦合. 一般的代码中.使用者即是生产者,使用者在调用它需要的对象的时候 ...

  3. ioc控制反转_深入理解依赖注入(DI)和控制反转(IOC)

    转载本文务必须注明出处.微信号(Yemeir_com).以及添加原文链接. 为什么要使用依赖注入 使用依赖注入(DI)可以使控制者与抽象实现者松耦合,便于单元测试.通过控制反转(IOC)的设计原理来减 ...

  4. python ioc di_PHP的依赖注入(DI) 和 控制反转(IoC)

    要想理解 PHP 依赖注入 和 控制反转 两个概念,就必须搞清楚如下的两个问题:DI -- Dependency Injection 依赖注入 IoC -- Inversion of Control ...

  5. 控制反转IOC与依赖注入DI

    为什么80%的码农都做不了架构师?>>>    1. IoC理论的背景 我们都知道,在采用面向对象方法设计的软件系统中,它的底层实现都是由N个对象组成的,所有的对象通过彼此的合作,最 ...

  6. 控制反转IOC、依赖注入DI的详细说明与举例

    文章目录 引入 IOC介绍 IOC的实现 通过构造函数注入依赖 通过 setter 设值方法注入依赖 依赖注入容器 IOC优缺点 优点 缺点 阅读时忽略语言差异,参考了很多其他博主内容,参考博文在最后 ...

  7. 依赖倒置(DIP),控制反转(IoC)与依赖注入(DI)

    DIP,IoC与DI概念解析 依赖倒置 DIP(Dependency Inversion Principle) DIP的两大原则: 1.高层模块不应该依赖于低层模块,二者都应该依赖于抽象. 2.抽象不 ...

  8. [教程]控制反转(IoC)与依赖注入(DI)

    来源: http://zhangjunhd.blog.51cto.com/113473/126530/ 挺简单的,说的也很清楚 ※IoC/DI 依赖Java的反射机制 1.控制反转(Inversion ...

  9. 控制反转(Ioc)和依赖注入(DI)

    控制反转IOC, 全称 "Inversion of Control".依赖注入DI, 全称 "Dependency Injection". 面向的问题:软件开发 ...

  10. 控制反转 IOC 与依赖注入 DI

    引言 简单总结和巩固一下spring的核心原理--IOC和DI的概念,为什么IOC要叫控制反转?IOC和DI的关系是怎样的? 一.IOC 控制反转 初学者可能很好奇,为什么spring framewo ...

最新文章

  1. 开挂的 00 后!17 岁「天才少女」被 8 所世界名校录取,最终选择 MIT 计算机系...
  2. 2021年春季学期-信号与系统-第五次作业参考答案-第二小题
  3. 在程序中集成地址簿、电子邮件和地图功能
  4. matlab调用c++生成dll32位与64位对应关系
  5. (1)memcached应用
  6. github怎么自动更新被人更新过的项目_GitHub 的这 8 个实用技巧,95%的人不知道...
  7. 【转】DICOM之Print!!!!!!!!!
  8. php 万分之一几率,那万分之一的概率啊……
  9. date转timestamp格式_技术分享 | MySQL:timestamp 时区转换导致 CPU %sy 高的问题
  10. php删除oracle数据记录日志文件,Oracle手动切换日志文件和清空日志文件
  11. 对于圣杯布局和双飞翼布局的新认识
  12. C语言 表白代码(I love you!)
  13. linux查cer证书信息,openssl 查看证书
  14. 3.Tom猫的实现(帧动画播放)
  15. 王牌投手·MLB棒球创造营
  16. OpenCV算法加速的一些学习总结
  17. 《沈剑架构师训练营》第7章 - 架构解耦
  18. TIA博途如何从DB数据块生成源文件或者源文件生成DB数据块?
  19. 有些爱意,在岁月中飘遥
  20. S32Kxxx bootloader之CAN bootloader

热门文章

  1. 极客大学架构师训练营 听课总结 - 架构视图,设计文档 -- 第二课
  2. SwiftUI资源列表
  3. Python列表和元组:[] ()
  4. BERT4Rec:知道用户的播放(购买、点击、...)序列 item1, item2, item3,预测下一个播放的item问题。
  5. 5G组网方案和频谱规划
  6. 395.至少有K个重复字符的最长子串
  7. ServletRequest--从html页面获取信息
  8. 材料之kube-dns.yaml
  9. 【POJ 3281】Dining【最大匹配、拆点】
  10. 我的世界android制作教程,《我的世界手机版》怎么制作mod制作JS教程图文攻略