依赖倒置原则 DIP(Dependence Inversion Principle)
依赖倒置原则 DIP(Dependence Inversion Principle) 控制反转(Inversion of Control,IoC) IoC就是DIP的一种具体思路,DIP只是一种理念、思想,而IoC是一种实现DIP的方法。 IoC的核心是将类(上层)所依赖的单元(下层)的实例化过程交由第三方来实现。 一个简单的特征,就是类中不对所依赖的单元有诸如 $component = new yiicomponentSomeClass() 的实例化语句。 . 依赖注入(Dependence Injection,DI) DI是IoC的一种设计模式,是一种套路,按照DI的套路,就可以实现IoC,就能符合DIP原则。 DI的核心是把类所依赖的单元的实例化过程,放到类的外面去实现。 控制反转容器(IoC Container) 当项目比较大时,依赖关系可能会很复杂。 而IoC Container提供了动态地创建、注入依赖单元,映射依赖关系等功能,减少了许多代码量。 服务定位器(Service Locator) Service Locator是IoC的另一种实现方式, 其核心是把所有可能用到的依赖单元交由Service Locator进行实例化和创建、配置, 把类对依赖单元的依赖,转换成类对Service Locator的依赖。 DI 与 Service Locator并不冲突,两者可以结合使用。 依赖注入 场景:假设要实现当访客在博客上发表评论后,向博文的作者发送Email的功能,通常代码会是这样: //为邮件服务定义抽象层 interface IEmailSender{ public function send(...$param); ... } //定义Gmail邮件服务 class GmailSender implements IEmailSender{ public function send(...$param){ ... } ... } //定义评论类 class Comment extends CommentDB{ //用于引用发送邮件的库 private $_eMailSender; //初始化时,实例化$eMailSender public function init(){ //这里假设使用Gmail邮件服务 $this->_eMailSender = new GmailSender(); } //当有新评论,即save()方法被调用之后中,会触发该方法 public function afterInsert(){ $this->_eMailSender->send(...$param); ... } } 试想如果现在我们不想使用Gmail邮件服务了,我们改用阿里云的或者自己的邮件服务,那么,你不得不修改 Comment::init() 里面对 $_eMailSender 的实例化语句:$this->_eMailSender = new GmailSender(); 不但违反了OO思想的开闭原则而且对于复用性、维护性、测试、扩展都带来了不便,不是不便而且非常不方便。 依赖注入就是为了解决这个问题而生的,当然,DI也不是唯一解决问题的办法,毕竟条条大路通罗马。 Service Locator也是可以实现解耦的。 //构造函数注入、属性输入 class Comment extends IComment{ private $_eMailSender; public function __construct($eMailSender){ $this->_eMailSender = $eMailSender; } //当有新评论,即save()方法被调用之后中,会触发该方法 public function afterInsert(){ $this->_eMailSender->send(...$param); ... } } //实例化两种不同的邮件服务,当然,他们都实现了EmailSenderInterface $sender1 = new GmailSender(); $sender2 = new MyEmailSender(); //用构造函数将GamilSender注入 $comment1 = new Comment($sender1); //使用Gmail发送邮件 $comment1->save(); //用构造函数将MyEmailSender注入 $comment2 = new Comment($sender2); //使用MyEmailSender发送邮件 $comment2->save(); 上面代码对比原来代码,解决了Comment类对于Gmail等具体类的依赖,将死的代码成活的的了(专业术语为:编译时转为运行时)。这种思想充分的展示了扩展性需要什么邮件服务类写出新的类即可、灵活性编译时转为运行时、复用性不论什么项目只要用到了邮件模块就可以使用,邮件模块具有独立性。 依赖注入容器 从上面DI两种注入方式来看,依赖单元的实例化代码是一个重复、繁琐的过程。 可以想像,一个Web应用的某一组件会依赖于若干单元,这些单元又有可能依赖于更低层级的单元, 从而形成依赖嵌套的情形。 参考文献: 依赖注入和依赖注入容器 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
- Swap Consumed very Much When PostgreSQL autovacuum to p
- Cocos2d-x 用lambda表达式实现监听,改变精灵的透明度和层级
- C#实现计算一个点围绕另一个点旋转指定弧度后坐标值的方法
- Oracle:“立即执行”是什么意思?
- 为什么在Ruby中未初始化的实例变量返回nil,但未初始化的类变
- GreenSock推出了新一代动画引擎平台GreenSock Animatio...
- Ajax提高篇(7)Ajax实现简单的下拉框联动显示数据
- 如何在Saxon中的XQuery中动态引用XML文件
- Powershell正则表达式:仅使用制表符替换多个空格
- oracle 修改某列属性