控制反转IoC简介

控制反转IoC简介

在实际的应用开发中,我们需要尽量避免和降低对象间的依赖关系,即降低耦合度。通常的业务对象之间都是互相依赖的,业务对象与业务对象、业务对象与持久层、业务对象与各种资源之间都存在这样或那样的依赖关系。但是如何才能做到降低类之间的依赖关系呢?这就是本文核心IoC需要解决的问题,下面从两大点具体介绍IoC:

(1)IoCDI的基本概念

        IoC(Inversion Of Control)即控制反转,其具体就是由容器来控制业务对象之间的依赖关系,而不是像传统方式中由代码来直接控制。控制反转的本质,是控制权由应用代码转到了外部容器,控制权的转移即是所谓的反转。控制权的转移带来的好处就是降低了业务对象之间的依赖程度,即实现了解耦。

         IoC的实现策略有两种:

1)依赖查找:容器中的受控对象通过容器的API来查找自己所依赖的资源和协作对象。这种方式虽然降低了对象间的依赖,但是同时也使用到了容器的API,造成了我们无法在容器外使用和测试对象;

2)依赖注入(又称DIDependency Injection):对象只提供普通的方法让容器去决定依赖关系,容器全权负责组建的装配,它会把符合依赖关系的对象通过属性或者是构造函数传递给需要的对象。通过属性注射依赖关系的做法称为设值方法注入,将构造子参数传入的做法称为构造子注入。

依赖注入的好处如下:

查询依赖操作和应用代码分离;

受控对象不会使用到容器的特定的API,这样我们的受控对象可以搬出容器单独使用。

(2)IoC模式的实例讲解

IoC代表的是一种思想,也是一种开发模式,但它不是什么具体的开发方法。要理解IoC的概念,最简单的方式就是看它的实际应用,下面将着重介绍几个实例来讲解IoC的内涵。

我们在开发一个应用系统时,会需要开发大量的Java类,系统将会通过这些Java类之间的相互调用来产生作用。类与类之间的调用关系是系统类之间最直接的关系。因此,我们可以将系统中的类分为两类:调用者和被调用者。具体如下图一所示:

图一:调用方法问题

软件设计方法及设计模式的发展,共产生了三种类调用的方法:自己创建(new)、工厂模式(get)、外部注入(set),其中外部注入即为IoC/DI的模式。

无论是哪一种方法,都存在两个角色——调用者和被调用者。下面我们通过实例来讲解这三种方法的具体含义。首先,我们设定调用者对象为学生对象Student,被调用者对象为图书对象Book,要设计的代码功能是学生学习图书知识。

从GoF设计模式中,我们已经习惯一种思维编程方式:Interface Driven Design接口驱动,接口驱动有很多好处,可以提供不同灵活的子类实现,增加代码稳定和健壮性等。为了演示不同的方法在Student取得不同Book对象时的区别,我们采用接口来设计被调用者,实现的代码如下面三个类所示:

//Book接口类
public interface IBook{
        public void learn();
}
//BookA实现类
public class BookA implements IBook{
        public void learn(){
               System.out.println("学习BookA");
        }
}
//BookB实现类
public class BookB implements IBook{
        public void learn(){
               System.out.println("学习BookB");
        }
}

其中IBook为图书的接口,它定义了一个学习接口learn(),并定义了两个图书类BookA和BookB来实现该接口,表示是两本不同的图书,其中learn()方法分别表示不同图书学习过程。

下面将从这三种方法讲解如何调用图书类:

  1)new——自己创建

Student要学习BookA,就要定义一个learnBookA()的方法,并自己来创建BookA的对象;同样,要学习BookB,就要定义一个learnBookB()的方法,并自己来创建BookB的对象。然后我们建立一个测试类Test.java来创建一个Student对象,可以分别调用learnBookA()和learnBookB()方法来分别执行两本书的学习过程。具体实现代码如下:

//学生类
public class Student{
      public void learnBookA(){
          IBook book = new BookA();
          book.learn();
      }
      public void learnBookB(){
          IBook book = new BookB();
          book.learn();
      }
}
//测试运行
public class Test{
      public static void main(){
           Student student = new Student();
           student.learnBookA();
           student.learnBookB();
      }
}

该方法在调用者Student需要调用被调用者IBook时,需要由自己创建一个IBook对象。这种做法的缺点是,无法更换被调用者,并且要负责被调用者的整个生命周期。具体形式如下图二所示:

图二:自己创建方式

  2)get——工厂模式

一切对象都由自己创建的缺点是,每一次调用都需要自己来负责创建对象,创建的对象会到处分散,造成管理上的麻烦,比如异常处理等。因此,我们可以将对象创建的过程提取出来,由一个工厂(Factory)统一来创建,需要什么对象都可以从工厂中取得。

例如下例中,我们创建了一个工厂类BookFactory,为该类添加两个函数getBookA()和getBookB(),分别用于创建BookA和BookB的对象。然后再创建Student中learnBookA()和learnBookB()中的方法,改为分别在该工厂类中取得这两个对象。具体实现代码如下;

//图书工厂
public class BookFactory{
       public static IBook getBookA(){
            IBook book = new BookA();
       }
       public static IBook getBookB(){
            IBook book = new BookB();
       }
}
//学生类
public class Student{
       public void learnBookA(){
            IBook book = BookFactory.getBookA();
            book.learn();
       }
       public void learnBookB(){
            IBook book = BookFactory.getBookB();
            book.learn();
       }
}
//测试运行
public class Test{
       public static void main(){
             Student student = new Student();
             student.learnBookA();
             student.learnBookB();
       }
}

此时与第一种方法的区别是,多了一个工厂类,并将Student中创建对象的代码提取到了工厂类,Student直接从工厂类中取得要创建的对象。这种方法的优点是,实现了对象的统一创建,调用者无须关心对象创建的过程,只管从工厂中取得即可。具体形式如下图三所示:

 

图三:工厂模式

这种方法实现了一定程度的优化,使得代码的逻辑也更趋向于统一。但是,对象的创建依然不灵活,因为对象的取得完成取决于工厂,又多了中间一道工序。

  3)set——外部注入

显然,第一种方式依赖于被调用者对象,第二种方式依赖于工厂,都存在依赖性。为了彻底解决依赖性的问题,我们又取消了工厂类,并仅仅为Student添加一个学习的方法learnBook(),输入的参数是接口类型IBook。在使用Student的方法时,我们先创建IBook的具体对象,然后再把该对象作为learnBook()的输入参数注入到Student,调用接口IBook的统一方法learn()即可完成学习过程。具体实现代码如下所示:

//学生类
public class Student{
       public void learnBook(IBook book){
             book.learn();
       }
}
//测试运行
public class Test{
       public static void main(){
              IBook bookA = new BookA();
              IBook bookB = new BookB();
              Student student = new Student();
              student.learnBook(bookA);
              student.learnBook(bookB);
       }
}

这样我们完全简化了Student类的方法,learnBook()的方法不再依赖于某一个特定的Book,而是使用了接口类IBook,这样只要在外部创建任意IBook的实现对象输入到该方法即可,使得Student类完全解脱了与具体某一种Book的依赖关系。上例中的Test.java,分别创建了bookA和bookB对象,同样都可以调用Student的learnBook()方法,使得Student变得完全通用。具体形式如下图四所示:

图四:外部注入方式

可见,set——外部注入方式完全抛开了依赖关系的枷锁,可以自由的由外部注入,这就是IoC,将对象的创建个获取提前到外部,由外部容器提供需要的组件。

时间: 2024-11-06 12:10:28

控制反转IoC简介的相关文章

iOS控制反转(IoC)与依赖注入(DI)的实现

背景 最近接触了一段时间的SpringMVC,对其控制反转(IoC)和依赖注入(DI)印象深刻,此后便一直在思考如何使用OC语言较好的实现这两个功能.Java语言自带的注解特性为IoC和DI带来了极大的方便,要在OC上较好的实现这两个功能,需要一些小小的技巧. 控制反转和依赖注入 控制反转 简单来说,将一个类对象的创建由手动new方式改为从IOC容器内获取,就是一种控制反转,例如我们现在要创建一个ClassA类,则常规方法为 ClassA *a = [ClassA new]; 如果使用控制反转,

控制反转IOC与依赖注入DI

1. IoC理论的背景我们都知道,在采用面向对象方法设计的软件系统中,它的底层实现都是由N个对象组成的,所有的对象通过彼此的合作,最终实现系统的业务逻辑. 图1:软件系统中耦合的对象 如果我们打开机械式手表的后盖,就会看到与上面类似的情形,各个齿轮分别带动时针.分针和秒针顺时针旋转,从而在表盘上产生正确的时间.图1中描述的就是这样的一个齿轮组,它拥有多个独立的齿轮,这些齿轮相互啮合在一起,协同工作,共同完成某项任务.我们可以看到,在这样的齿轮组中,如果有一个齿轮出了问题,就可能会影响到整个齿轮组

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

控制反转IOC, 全称 “Inversion of Control”.依赖注入DI, 全称 “Dependency Injection”. 面向的问题:软件开发中,为了降低模块间.类间的耦合度,提倡基于接口的开发,那么在实现中必须面临最终是有“谁”提供实体类的问题.(将各层的对象以松耦合的方式组织起来,各层对象的调用面向接口.) 当一个类的实例需要另一个类的实例协助时,在传统的程序设计过程中,通常有调用者来创建被调用者的实例. 然后,采用依赖注入原则,创建被调用者的实例的工作不再由调用者完成,而

话说 依赖注入(DI) or 控制反转(IoC)

首页 下载 扩展 应用 教程 代码 案例 资讯 讨论 全部 搜索 话说 依赖注入(DI) or 控制反转(IoC) 浏览:3641 发布日期:2014/03/20 分类:技术分享 科普:首先依赖注入和控制反转说的是同一个东西,是一种设计模式,这种设计模式用来减少程序间的耦合,鄙人学习了一下,看TP官网还没有相关的文章,就写下这篇拙作介绍一下这种设计模式,希望能为TP社区贡献一些力量. 首先先别追究这个设计模式的定义,否则你一定会被说的云里雾里,笔者就是深受其害,百度了N多文章,都是从理论角度来描

Spring.NET 控制反转(IoC)和环境配置

using System; using System.Collections.Generic; using System.Linq; using System.Text; using Spring.Context; using Spring.Context.Support; using Common.Logging; namespace Test2 { /// <summary> /// 在学习Spring.NET这个控制反转(IoC)和面向切面(AOP)的容器框架之前,我们先来看一下什么是控

什么是控制反转IOC

1.IOC 是什么 IOC- Inversion of Control , 即"控制反转" ,不是一个技术,而是一个设计思想,在java 开发中,IOC意味着将你设计好的Java 对象交个容器控制,而不是传统的在你的对象内部直接控制,想要理解好IOC ,关键是要明确" 谁控制谁,控制什么,为何是反转,什么反转了?" * 谁控制谁,控制什么: 在传统的 Java SE 设计中,我们直接在java 对象的内部通过new 进行创建对象,是程序自动的去创建对象,而 IOC

控制反转IOC与依赖注入DI - 理论篇

学无止境,精益求精 十年河东十年河西,莫欺少年穷 昨天是五一小长假归来上班的第一天,身体疲劳,毫无工作热情.于是就看看新闻,喝喝茶,荒废了一天 也就在昨天,康美同事张晶童鞋让我学习下IOC的理论及实现,毕竟是之前的好同事,好朋友,我也就抽时间百度了很多资料 在查阅网上资料的过程中,我发现大多技术篇幅都是IOC的代码实现,并没有一篇介绍IOC理论的篇幅!这显然不是我想要的. 我知道要想搞明白IOC,就必须要弄明白什么是IOC(控制反转)?为什么叫IOC(控制反转)?为什么之后又可以称为DI(依赖注

【Java_Spring】控制反转IoC(Inversion of Control)

1. IOC的概念 控制反转IoC(Inversion of Control)是一种设计思想,而DI(依赖注入)是实现IoC的一种方法.在没有使用IOC的程序中,对象间的依赖关系是靠硬编码的方式实现的.引入IOC后对象的创建由程序自己控制的,控制反转即将对象的创建交给第三方,个人认为所谓控制反转就是:获得依赖对象的方式反转了. IoC是Spring框架的核心内容,在IOC容器中一切对象皆为Bean组件.IOC容器通过读取XML配置文件中的Bean信息,产生每个Bean实例.使用多种方式完美的实现

C#依赖注入控制反转IOC实现详解

原文:C#依赖注入控制反转IOC实现详解 IOC的基本概念是:不创建对象,但是描述创建它们的方式.在代码中不直接与对象和服务连接,但在配置文件中描述哪一个组件需要哪一项服务.容器负责将这些联系在一起. 举个例子,组件A中有类ClassA,组件B中有接口IB和其对应的实现类B1和B2. 那么,现在ClassA需要利用IB接口来做一些事情,例如: public class ClassA { public void DoSomething() { IB b = ??? b.DoWork(); }} 现