浅谈依赖注入与控制反转

前言:设计模式其实是一个很空洞的东西,设计模式有几十种,有些人觉得工厂模式也单例模式已经足够解决大部分问题。而有些人觉得任何设计模式都会让开发变得更“复杂”,更“低效”。所以千万不要太过追求他的实际意义和作用,否则你已经坠入云雾。但是不管怎么样,实际工作中还是要对它们有所了解,下面从php的角度来讲一下依赖注入、控制反转、反射等概念。如有错误之处,还望路过大神多加指点

首先设定场景,假如一个类需要数据库连接,最简单的做法可能是:

    class example {
        private $_db;
        function __construct(){
            include "./Lib/Db.php";
            $this->_db = new Db("localhost","root","123456","test");
        }
        function getList(){
            $this->_db->query("......");
        }
    }

但事实上稍微有点经验的同学都不会这样写,因为一旦越来越多的类用到db,而db一旦发生变化,那么岂不是要每个文件都修改一遍?这就是程序设计中的耦合问题。所有的类过度依赖 "./Lib/Db.php" 这个文件。OK,为了解决这个问题,工厂模式出现了,我们新建一个 Factory 工厂类:

    class Factory {
        public static function getDb(){
            include "./Lib/Db.php";
            return new Db("localhost","root","123456","test");
        }
    }
    class example {
        private $_db;
        function __construct(){
            $this->_db = Factory::getDb();
        }
        function getList(){
            $this->_db->query("......");
        }
    }

如果我们用到db模块那么直接 Factory::getDb() 从工厂中取出来就是了,看似解决了问题。但事实是这样吗?不,这样只不过是把程序与 db 模块的耦合转移到了 Factory ,一旦后期业务发生变动,Factory 发生变动,依旧要对每个文件改动。那如何解决呢?

我们可以不从example类内部获取db组件,我们从外部把db组件注入进example类

    class example {
        private $_db;
        function getList(){
            $this->_db->query("......");//执行查询
        }
        //从外部注入db连接
        function setDb($connection){
            $this->_db = $connection;
        }
    }
    $example = new example();
    $example->setDb(Factory::getDb());//注入db连接
    $example->getList();

这样一来example就不用关心db组件怎么来的了,只用暴露一个注入方法即可。这就是DI/依赖注入(Dependency Injection),不在内部处理依赖关系,而是把依赖作为参数传递进去,以降低程序的耦合性。

然后我们的项目继续进行,用到了文件处理类,图像处理类,我们可能会这样写

$example->setDb(Factory::getDb());//注入db连接
$example->setFile(Factory::getFile());//注入文件处理类
$example->setImage(Factory::getImage());//注入Image处理类

但是这样似乎也不行啊,每次都要写这么多代码,于是我们又写了一个工厂方法

    class Factory {
        public static function getExample(){
            $example = new example();
            $example->setDb(Factory::getDb());//注入db连接
            $example->setFile(Factory::getFile());//注入文件处理类
            $example->setImage(Factory::getImage());//注入Image处理类
            return $expample;
        }
    }

example也不直接new 了。我们用 Factory::getExample()中获取。但是,这是不是又有点熟悉的感觉?和上面第一次用工厂类的时候一样依赖于工厂。于是又有了容器的概念。

class example {
    private $_di;
    function __construct(Di &$di){
        $this->_di = $di;
    }
    //通过di容器获取db实例
    function getList(){
        $this->_di->get(‘db‘)->query("......");
    }
}
$di = new Di();
$di->set("db",function(){
   return new Db("localhost","root","root","test");
});
$example = new example($di);
$example->getList();

Di就是一个存放各种可扩展的组件的容器,需要注入的时候调用$di->set()方法注入组件即可。程序中即可通过$di->get() 获取组件。这样被调用的组件(db)并不是由调用者(example)创建,而是由Di容器创建,调用者失去控制权,而容器得到控制权,发生了控制权转移,所以叫做控制反转(Inversion of Control)

但是这样又有一些比较有强迫症的同学发现了,每个类都要注入一遍容器是不是有些麻烦。没错,其实注入容器这个动作可以交给另外的程序处理,那就是反射。

<?php
/**
* example
*/
class example {
    //通过di容器获取db实例
    function getList(){
        $this->_di->get(‘db‘)->query("......");
    }
}
//di容器
class Di{
    public $_container;
    public function get($cls){
        return $this->_container[$cls];
    }
    public function set($cls,$_instance){
        $this->_container[$cls]=$_instance;
    }
}
//db组件
class db{
    private static $_instance;//保存单例
    //单例方法
    public static function getInstance(){
        if(!(self::$_instance instanceof self)){
            self::$_instance = new self;
        }
        return self::$_instance;
    }
    //查询方法
    public function query($sql){
        echo $sql;
    }
}

$di = new Di();//实例化容器
$di->set(‘db‘,db::getInstance());   //注入db实例

$reflector = new ReflectionClass(‘example‘);    //反射example,通过反射可以获得该类的所有信息
$reflector->getDefaultProperties();             //example属性
$reflector->getDocComment();               //注释

$instance =$reflector->newInstanceArgs();       //相当于实例化反射的example类
$instance->_di=$di;                             //注入di容器

$reflector->getmethod(‘getList‘)->invoke($instance);//调用example类方法

通过反射我们可以得到该类的全部信息,包括方法、方法名、属性甚至注释等等。通过反射我们可以方便的控制程序中使用的类,对他们进行扩展、修正、以及监听。通常反射在插件开发和框架开发中大量应用。在框架开发中也会把反射与依赖注入、控制反转搭配使用,让程序有强大的可控性和扩展性。

eg:反射主要是用在“单一出口”的情况下使用,比如mvc框架,基本上都是由框架核心类解析url,得到指向的文件名类名方法名,然后加载对应的控制器文件,然后用反射注入容器就可以了,并不需要每次都写。

时间: 2024-11-18 18:24:04

浅谈依赖注入与控制反转的相关文章

PHP 依赖注入和控制反转再谈(二)

今天有个朋友看到yii2中介绍的依赖注入一头雾水,之前我写过类似的文章发给他看了,可能还没深入理解吧,这里我再通俗点描述下依赖注入的原理吧,尽可能滴说通俗易懂一点吧:先还是扯下概念性滴问题(概念问题我个人的原则总是先简单瞟一眼概念,通过实例来对概念加深理解了) 要想理解 PHP 依赖注入 和 控制反转 两个概念,我们还是必须搞清楚下面的两个问题: DI -- Dependency Injection 依赖注入 IoC -- Inversion of Control 控制反转 什么是依赖注入 没有

谈谈php依赖注入和控制反转

要想理解php依赖注入和控制反转两个概念,就必须搞清楚如下的问题: DI--Dependency Injection   依赖注入 IoC--Inversion of Control  控制反转 1.参与者都有谁? 答:一般有三方参与者,一个是某个对象:一个是IoC/DI的容器:另一个是某个对象的外部资源.又要名词解释一下,某个对象指的就是任意的.普通的Java对象; IoC/DI的容器简单点说就是指用来实现IoC/DI功能的一个框架程序:对象的外部资源指的就是对象需要的,但是是从对象外部获取的

Spring 的核心机制:依赖注入(控制反转)

一.说到依赖注入(控制反转),先要理解什么是依赖. Spring 把相互协作的关系称为依赖关系.假如 A 组件调用了 B 组件的方法,我们可称A 组件依赖于 B 组件. 二.什么是依赖注入. 在传统的程序设计过程中,通常由调用者来创建被调用者的实例. 在依赖注入的模式下,创建被调用者的工作不再由调用者来完成,因此称为控制反转:创建被调用者实例的工作通常由Spring 容器来完成,然后注入给调用者,因此也称为依赖注入. 三.依赖注入的好处. 依赖注入让 Spring 的 Bean 以被指文件组织在

php之依赖注入和控制反转

  DI——Dependency Injection   依赖注入  IoC——Inversion of Control  控制反转  要想理解上面两个概念,就必须搞清楚如下的问题: 1.参与者都有谁? 答:一般有三方参与者,一个是某个对象:一个是IoC/DI的容器:另一个是某个对象的外部资源.又要名词解释一下,某个对象指的就是任意的.普通的Java对象; IoC/DI的容器简单点说就是指用来实现IoC/DI功能的一个框架程序:对象的外部资源指的就是对象需要的,但是是从对象外部获取的,都统称资源

反射机制、依赖注入、控制反转

反射机制 正向: 代码->dll, 先编码, 定义好类,通过实例化对象来调用之. 反向: dll->类[方法,属性]. 从已经有的dll文件反编译得到其中的一些可用的方法. 审查元数据并收集关于它的类型信息的能力.元数据(编译以后的最基本数据单元)就是一大堆的表,当编译程序集或者模块时,编译器会创建一个类定义表,一个字段定义表,和一个方法定义表等. System.reflection命名空间包含的几个类,允许你反射(解析)这些元数据表的代码. 反射是.Net中获取 运行时类型信息的方式,.Ne

Java的依赖注入(控制反转)

两个主角"依赖注入"和"控制反转": 1.二都说的都是同一件事,只是叫法不同.是一个重要的面向对象编程的法则,也是一种设计模式: 2.英文原称:依赖注入,Dependency Injection(DI); 控制反转,Inversion of Control(IoC). 3.作用:削减计算机程序的耦合问题: 4.为什么叫"控制反转":创建被调用者的工作不再由调用者来完成,因此称为控制反转.结合Java说,当某个Java实例需要其他Java实例时,系

(转)依赖注入和控制反转

发现一篇介绍依赖注入和控制反转的文章,特转载以备后用. 文章地址1:http://baitai.iteye.com/blog/792980 相关文章:http://www.cnblogs.com/DebugLZQ/archive/2013/06/05/3107957.html: http://www.cnblogs.com/xingyukun/archive/2007/10/20/931331.html: http://www.cnblogs.com/zhenyulu/articles/6417

简单解析依赖注入(控制反转)在Spring中的应用

IoC——Inversion of Control  控制反转DI——Dependency Injection   依赖注入 大家都知道,依赖注入是Spring中非常重要的一种设计模式.可能很多初学者对这种看起来高深的东西有一种抗拒,这里就 简单介绍一下到底什么是依赖注入,Spring到底又到底是如何运用依赖注入的. 依赖关系:在A组件中要引用B组件的对象,则称A依赖于B依赖关系会造成各组件之间的硬编码,为解决依赖关系,一般的解决方法如下: 1.A组件先创建B组件,在调用B组件方法2.A组件先通

依赖注入和控制反转

依赖注入: A类依赖着B类,如下: public A{ private B b; public void showB(){ b= new B(); System.out.println(b); } } 我们可以通过spring配置或者注解的方式去注入依赖类,从而做到每次使用依赖类时无须手动去实例化依赖类,这就是所谓的依赖注入. 控制反转: 我们通过spring提供的ApplicationContext对象(代表一个spring控制反转容器)去控制去操作容器中的类,而不是以往我们自己去创建类去操作