• 561

如何理解IoC(Inversion of Control)?

RT,如何理解IoC(Inversion of Control)?如果能写个demo解释最好了。

阅读 6.5k
评论 2014-11-03 提问
    17 个回答
    • 21.8k

    我试着搜了一下,中文资料基本都把IoC(控制翻转)和DI(依赖注入)混为一谈,就连StackOverflow上的第一位答案也犯了同样的问题(幸好下面有高票的反对评论,否则我的世界观都快坏掉了)

    控制翻转是代码复用的一种模式(注意不是设计模式)

    一般(非IoC)的复用,通常是用户代码调用组件(任意形式的被复用的代码,本答案中统称为组件)。也就是用户代码解决“Why it works, What to do”,组件解决“How to do”,逻辑的入口是用户代码,

    而控制翻转则是组件来调用用户代码,也就是组件解决“Why it works, When to do”,用户代码解决“What to do”,逻辑的入口是组件

    下面是除了DI之外的控制翻转的例子

    • 接口/虚函数 组件调用接口/虚函数,具体由用户代码实现
    • 发布订阅(事件)模式 组件触发事件,用户代码订阅事件
    • 回调 用户代码写回调,组件来调用
    • 几乎所有能被称之为框架的东西 用户代码在规定的地方实现具体业务逻辑,剩下的框架负责
      • 3.3k

      通俗的说,一个项目由各个类组成。一个类在一个项目会被很多地方使用。

      如果按照传统的写法就是每个用的地方都需要 new Class()
      如果参数很复杂,每个地方都需要new Class(param1, param2, param3, ..)
      此时每次修改类的构造函数, 那么每个地方需要跟着修改。工作量大,耦合度高。

      但是可以把需要使用的类,初始化一次,放到一个容器中保存起来,其他需要使用的地方,
      只需要调用容器的方法Container->getClassINeed()
      那么,使用这个类和生成这个类通过中间的容器分开了。
      示例可以看Phalcon框架,文档里给的例子,教你一步步搭建自己的容器

      一些管理对象生成的设计模式,本身也算一种容器的实现, 例如常见的工厂模式

        • 69

        IoC就是让框架为我们创建些东西。

        App::bind('sms', function () {
           // Create a new SMS component.
           $sms = new SMSClient;
           $sms->setUsername('shauna');
           $sms->setPassword('1_5t341_c4t5!');
           // Return the created SMS component.
           return $sms;
        });
        

        据Clouser function特征,上面代的代码不会创建$sms对象。
        $app->make('sms')的时候,$sms对象才被创建。所谓的反转大概就是按需创建吧。用的时候才触发创建,不是创建好了等着用。

        因为程序员本身是农民工的一种,但是又想装的高大上一些,用以自赏,所以创建了这个很NB的术语,装的好像搞原子弹的。不用太在意。

          • 46.8k

          Don't call me, I will call you

          正常流程

          你去图书馆借书,但是没有。

          于是你回家了。

          然后你每个天去一趟图书馆,看你的书到了没有。

          如果还没有,那么你回家,继续等……

          第二天,再去看,……

          一直到有了这本书。

          Ioc

          你去图书馆借书,但是没有。

          于是你登记了一下,就回家了。

          回到家,刷刷微博,刷刷sf,撸撸代码。

          等书到了,管理员通知你。

          你去拿书。


          Don't call me, I will call you

            本质是面向抽象编程,IOC描述的是特性,DI描述的具体实现方式,两者有共通的地方。可以这么理解:用DI实现具备IOC特性的框架,最终体现面向抽象编程的理念,增强系统的可扩性。
            常见的“多态”就是面向抽象编程,比如:

            Person person = new Male();
            person.say();
            person.run();
            person.eat();
            

            现在要把person指定为Female,则只需替换第一行即可:

            Person person = new Female();
            

            改动已经很少了,但仍可以做得更彻底一点:可不可以不更改现有代码就完成切换呢?答案就是"DI"。
            撇开Spring不谈,咱们自己也完全可以实现一套最简化的类似功能:

            Person person = SpringLike.getBeanFromConfig('person');
            

            这行代码的意思就是,Person的实例是根据配置文件产生的,比如:

            person=com.xx.Male
            

            具体原理不赘述,大家耳熟能详。
            回到上面那个问题,现在要把功能切换到Female,则只需更改配置文件即可:

            person=com.xx.Female
            

            将控制权进一步转移到配置文件,因而修改不涉及业务逻辑代码。
            可以看出,“DI”是用更彻底的方式使用多态,在面向抽象编程这方面走得更远。"IOC"是面向抽象编程所体现出来的一个特性,本身和“DI”不冲突。

              • 2.1k

              举个例子,有一天,你去庆丰包子铺吃包子,进门后你首先需要找到点餐台在哪,然后告诉服务员你要什么,然后去领餐口领包子。这是以你为主的流程,一切都在你的掌握之下,但如果你不主动,就没有包子吃。

              第二天,你去另一家高大上包子铺吃包子,这里,你只要坐下来说一句我要吃包子,就有服务员给你把包子端上来。这是以餐厅为主的流程,你不需要知道去哪点餐,去哪领包子。

              如果把第一个流程作为“正”的话,那第二个流程就是“反”过来了。这就是所谓的IoC。不过,这个名字起的不太容易理解,因为正、反的概念是相对的,你也可以说第二个流程是正的。

              把这个概念应用到GUI编程上,就是顺序执行和事件处理的区别。本来是你自己写的程序按顺序执行,例如第一步输入用户名,第二部输入密码,然后执行登录操作。使用了Windows或者其他图形界面框架后,就是由框架来负责运行你的程序,并且在用户输入了内容之后通知你的程序,你再去做处理。相对于顺序执行,事件驱动就是IoC的一种表现形式。

              把这个概念应用到依赖管理上,假设你的程序需要引用另一个对象,本来你是需要在代码里创建这个对象,应用IoC模式后,你的程序不再去主动创建第三方对象,而是运行在一个容器或者框架里,例如Spring,然后等着Spring把你需要的对象创建好传递进来。这就是依赖注入(DI),IoC的另一种表现形式。

                • 3.8k

                  建议看看spring框架的原理,就是依赖注册

                    正常的写法,都是上层调用底层封装好的方法,由底层提供接口,所谓的控制反转指的是,底层的执行逻辑可以由上层来决定,写的是什么,底层就执行什么,它的好处在于灵活、易扩展,就像@bigxu 写的代码一样。

                      • 3
                      • 新人请关照

                      顧名思義吧,你寫出的程式是在操縱些什麼,比如說,給一些數據搬家,但是怎麼來指揮你的程式開始操控它要操控的對象呢?那麼你有要寫一些程式來做指(調)揮(用)你的程式,你定義一個規則,或者遵循一套規則,以便讓人來操控自身,其實這就是控制反轉,即,你是要把控制權交給別人的,仔細想想,其實這種反轉無處不在,更重要的是,怎麼讓別人來調用你的程式?需要約定接口,所以IoC也引導你更多的從面向接口方面考慮編程問題

                        IoC,控制反转,把对XX的控制交给别人。
                        spring的DI就是你把new对象的工作交给spring。

                          ioc 通俗一点的说,你把他想成一个大工厂,你问他要什么object,他就给你什么object,就是这么简单
                          他就像一个全局变量,在每个object里面的都可以访问到
                          你问他要什么object,他就给你什么object

                            ioc主要作用是用来解析类的实例,为什么要解析?而不是直接获得?因为类有其他类的依赖关系。ioc容器可以把多层级的依赖关系全部解析出来。

                            如果你看的是Laravel框架,可以看看:Service Container(IOC容器)

                              依赖注入和控制反转都是为了达到相同的解耦效果,Ioc确实不够开门见山,因此业界称进行了广泛的讨论,最终软件界的泰斗级人物Martin Fowler提出了DI的概念用以替代Ioc,即让调用类对某一接口实现类的依赖关系都第三方(容器或协作类)注入,以移除调用类对某一接口实现类的依赖。

                                依赖注入是控制反转的一种实现方式。

                                  • 1.8k

                                  IOC可以通俗理解:

                                  比如我要去ATM取款,我有一堆银行卡:农行、建行

                                  IOC处理的就是通过ATM的接口(当然也包括系统)去约束卡

                                  比如,卡的大小要求,卡要有磁条,然后得有余额;这些元素都是取款的必备条件。ATM就约束了卡。

                                  IOC的精髓就是:取款操作一致,而卡却不一样。而能使用的卡则依靠中间者(ATM机)去约束

                                    撰写回答

                                    登录后参与交流、获取后续更新提醒