我理解的IOC技术在Java和C#中比较分析

  一直想用心写这个系列的文章,其实看得越多,也就越觉得自己在这方面的功力太浅,也就越不想班门弄斧啦,作为一个开篇,我想把这个技术深层次化,在之前的.net的一个MVC系列文章其实已经涉及到了,只是.net在这方面的应用不如java来得这么猛烈,这么酣汗淋漓,所以也就下定决心,这一阶段针对这一个技术点进行深层次的剖析。

  IOC,英文全称Inversion of Control,中文直译控制反转,一般我们称之为“依赖注入”原则,在我还未过多涉足java领域时,在C#语言24个设计模式中(参见《大话设计模式》)有一个依赖倒转原则,作为一个设计模式的原则而不是一个模式。在接触java之后,尤其是spring框架后,被称之为“依赖注入”IOC设计模式。其实大体的意思和意义都是差不多的,只是在我看来,在C#领域对这个技术的应用没有那么广泛,限于.NET技术的先天性,我很少看到这方面的巨作,也许是我太肤浅。在我上次写基于.NET的MVC ProDinner系列文章时候,查找这方面的文章,几乎是为零,只能自己去看MVC源码或者Castle 项目源码。

  首先看看《大话设计模式》中基于C#语言如何诠释这门艺术的。原著由维修计算机入题,在我们日常生活中,我们很自然地,提高计算机速度需要更高的CPU,需要更快的系统响应度就需要更好的内存,需要更大的存储介质,就需要扩大硬盘,在这一系列的活动中,于是我们就自然而然的发现,计算机速度依赖CPU,在CPU的使用中我们从来不关心CPU是怎么设计出来的,我们只需要关注这是Intel还是AMD的CPU,因为他决定了你的主板类型,当确定了CPU之后,我们只需关注你需要使用那款CPU,因为接口主板都是一样的,也即是说,大的功能不会去关注具体每一款产品的实现,而只需要关注产品与产品之间的标准化接口。由此引出来这个原则的定义:

  A、高层模块不应该依赖低层模块,两个都应该依赖抽象

  B、抽象不应该依赖细节,细节应该依赖抽象

  这么讲其实是比较抽象的,具体到代码中实际上就是,层于层之间,各模块间,各项目间都应该使用接口层来完成模块的融合。 当某个角色(可能是一个对象实例,调用者)需要另一个角色(另一个对象实例,被调用者)的协助时,在传统的程序设计过程中,通常由调用者来创建被调用者的实例。而控制反转中创建被调用者的工作不再由调用者来完成。创建被调用者 实例的工作通常由特定的容器来完成,然后注入调用者,因此也称为依赖注入。

  废话不多说,理论讲得再精彩最终看代码实现,依据我对这些该概念的理解,我们一起看基于C#语言写出的实例:

  需求场景:

父亲在完成一件事情的时候,由于各方面原因需要自己的子女帮忙才能完成,所以,父亲需要去调动自己的儿子或者女儿才能完成这件事情

  类型设计:

  接口 Iperson为被调用者的基类型

类 Father 调用者

类 Son 被调用者

  类 Daughter 被调用者

  类 Container 依赖注入容器

      程序分析:

Father类通过调用抽象层接口,来完成这个操作,至于调用儿子还是女儿我们在构造函数中完成类型的选择。也就是说Father是调用者,Son和Daughter是被调用者,Container是依赖注入的生成容器。负责将调用者Son或者Daughter对象实例化给调用者。

  .NET 程序目录结构:

  打开visual studio 建立控制台应用程序,接口层代码实现:

1     //接口层
2     public interface Iperson
3     {
4         void operation();
5     }

  调用者代码实现:

 1     //调用者实现类
 2     public class Father
 3     {
 4         Iperson iperson;
 5
 6         Container container = new Container();
 7
 8         public Father(String typeName)
 9         {
10             iperson = container.GetApplication(typeName);
11         }
12         public void operation()
13         {
14             iperson.operation();
15         }
16     }

Container 在这里我直接new出实例了,看到这个代码熟悉java spring框架的同学就似曾相识了,一般是用@autowired来修饰依赖注入的操作句柄。Father类中的operation方法并没有自己去实现任何操作,而是调用了iperson的操作来实现自己的方法,而iperson只是一个接口类型,需要具体的实现类,代码才能运行起来,我们看iperson的两个实现层:

    //被调用者类 ipseron实现层
    public class Son:Iperson
    {
        public void operation()
        {
            Console.WriteLine("son is the operator");
        }
    }

    //被调用者之二
    public class Daughter:Iperson
    {
        public void operation()
        {
            Console.WriteLine("daughter is the operator");
        }
    }

Conatiner是实现容器,原理其实很简单,反射技术,反射原理进行不同的封装其实就形成了不同的技术框架,java spring的ioc核心离不开反射,许多的数据库mapper框架同样也离不开反射,看看代码实现:

    //生成实例容器
    public class Container
    { 

        public Iperson GetApplication(String typeName)
        {
          return (Iperson) Activator.CreateInstance(Type.GetType(typeName));
        }
    }

当然,我这是最基本的反射实现了,在生成化产品化的框架中反射远没有这么简单,但原理都是相同的。好,看下测试类实现代码:

    class Program
    {
        static void Main(string[] args)
        {
            //调用son
            Father fa = new Father("IOCblog.Son");
            fa.operation();

            //调用daughter
            fa = new Father("IOCblog.Daughter");
            fa.operation();
        }
    }

程序运行结果:

代码写到这里对这个概念有所掌握的同学,其实会是有共鸣的,这是依赖注入最基本的实现了,日常项目开发中基于框架级别来实现这种模式思想,我们很多时候是用修饰符或者配置文件,典型的就是java下面的spring的实现。java spring框架可没那么简单,spring两大核心ioc和aop,实现的手段无非也是如此,但不同的是思想!思想!我这里如若再用java套spring框架来做示例实现java下的IOC的思想,肯定也就没人有兴趣继续看下去了,这篇文章的含金量就没那么诱人啦,那么我们来高级点的:

  基于java代码的模拟spring框架IOC实现

  实现java下的ioc毫无疑问,我们首先专业术语就换成了,我们需要JavaBean来实现注入,需要factory来实现容器,实现步奏:

  1、建立需要实现注入的JavaBean,注入类Person和容器类Persons

  2、建立类似spring框架的application.xml配置文件,将依赖的JavaBean和相应注入的属性配置在xml文件中,我们这里取名叫 IocApplication.xml

  3、实现注入容器的factory类,主要负责读配置文件->依据配置文件进行对象实例化->放入persons map集合当中,以备调用。

java程序目录结构:

大体实现思路如上所述,好,废话不多说,看看代码如何实现,第一步和第二步代码如下(切换到eclipse下,建立java应用程序):

package com.ioc.bean;

//被调用注入类
public class Person {

    private String name;
    public String getName()
    {
        return this.name;
    }

    public void setName(String name)
    {
        this.name = name;
    }

}
package com.ioc.bean;

//beans类
public class Persons {

    private Person son;
    public Person getSon()
    {
        return this.son;
    }

    public void setSon(Person son)
    {
        this.son = son;
    }

    private Person daughter;
    public Person getDaughter()
    {
        return this.daughter;
    }

    public void setDaughter(Person daughter)
    {
        this.daughter = daughter;
    }
}

实现的容器factory代码量比较大,这里就不依依贴出,所有的源代码都在附件中可自由下载,这里主要分析几个关键步奏:

实现容器,主要负责一件事件,通过配置的xml,对相应的javabean进行反射,生成实例化对象,存入map中,xml配置实现:

<?xml version="1.0" encoding="UTF-8"?>
<beans>
    <bean id="son" class="com.ioc.bean.Person">
        <property name="name">
            <value>mark</value>
        </property>
    </bean>
    <bean id="daughter" class="com.ioc.bean.Person">
        <property name="name">
            <value>cindy</value>
        </property>
    </bean>
    <bean id="father" class="com.ioc.bean.Persons">
        <property name="son">
            <ref bean="son" />
        </property>
        <property name="daughter">
            <ref bean="daughter" />
        </property>
    </bean>
</beans> 

容器实现map操作代码:

    private Map<String,Object> beanMap=new HashMap<String,Object>();  

    /**
     * 初始化xml文件
     * */
    public void init(String xmlUrl){
        SAXReader  saxReader=new SAXReader();
        File file=new File(xmlUrl);
        try{
            saxReader.addHandler("/beans/bean",new BeanHandler());
            saxReader.read(file);
        }
        catch(DocumentException e){
            System.out.println(e.getMessage());
        }
    }  

    /**
     * 根据beanid来获取bean
     * */
    public Object getBean(String beanId){
        Object obj=null;
        obj=beanMap.get(beanId);
        return obj;  

    }  
BeanHandler毫无疑问就是具体去操作IocApplication.xml文件的操作类,代码比较长,可以下载附件源代码查看。好,看下测试类代码:
package com.ioc.test;

import com.ioc.bean.Person;
import com.ioc.factory.BeanFactory;

public class Test {

    public static void main(String[] args) {
        // TODO Auto-generated method stub

        String xmlUrl="src/IocApplication.xml";
        BeanFactory factory=new BeanFactory();
        factory.init(xmlUrl);
        Person me=(Person)factory.getBean("son");
        System.out.println("Son‘s name:"+me.getName());
    }

}

程序运行结果:

java 模拟spring实现,可以参考这篇文章:http://only1.iteye.com/blog/733550

  结束语:

  这篇文章我们暂且不来比较依赖注入和反转的区别,依赖反转和依赖注入很多程序员把这两个概念当成一个理解,认为只是不同的解释,其实细分还是有区别的
  1、依赖注入是从应用程序的角度在描述,也就是说,应用程序依赖容器创建并注入它所需要的外部资源;而控制反转是从容器的角度在描述,容器控制应用程序,由容器反向的向应用程序注入应用程序所需要的外部资源。

  2、IOC,控制反转是软件运行时体现出来的一个特征:如果对象A运行时依赖于对象B,但A并不去创建B,而是从外界直接取得B。也就是说,一个对象并不是自己去创建它所依赖的其它对象。DI,依赖注入是控制反转的一种实现手段。如上面的例子,B的取得并不需要A的干涉,而是利用某些框架在通过构造参数或属性设置来实现。

关于这些这里就不展开叙述,后面我们再详细讨论,这节主要讨论依赖注入,我们首先在这节暂时认为这是一个相同的概念。作为概述,首先我们了解下IOC概念,再看看java和C#在这一概念上的运用比较。

写一篇博文基本是一个礼拜的积累,雕琢,不容易,无私的奉献转载注明出处,http://www.cnblogs.com/aspnetdream/p/4035677.html。

最后附上我的源代码

Java代码 http://files.cnblogs.com/aspnetdream/iocblog.rar

C#代码 http://files.cnblogs.com/aspnetdream/Csharp_IOCblog.rar

时间: 2024-10-13 08:13:07

我理解的IOC技术在Java和C#中比较分析的相关文章

如何理解Spring IOC

学习过spring框架的人一定都会听过Spring的IoC(控制反转) .DI(依赖注入)这两个概念,对于初学Spring的人来说,总觉得IoC .DI这两个概念是模糊不清的,是很难理解的,今天和大家分享网上的一些技术大牛们对Spring框架的IOC的理解以及谈谈我对Spring Ioc的理解. 一.开涛对Ioc的讲解 原文  开涛的博客 1.IoC是什么 Ioc-Inversion of Control,即"控制反转",不是什么技术,而是一种设计思想.在Java开发中,Ioc意味着将

深入理解Spring IOC

转载自 http://www.cnblogs.com/xdp-gacl/p/4249939.html 学习过Spring框架的人一定都会听过Spring的IoC(控制反转) .DI(依赖注入)这两个概念,对于初学Spring的人来说,总觉得IoC .DI这两个概念是模糊不清的,是很难理解的,今天和大家分享网上的一些技术大牛们对Spring框架的IOC的理解以及谈谈我对Spring Ioc的理解. 一.分享Iteye的开涛对Ioc的精彩讲解 首先要分享的是Iteye的开涛这位技术牛人对Spring

以网游服务端的网络接入层设计为例,理解实时通信的技术挑战

本文参考并引用了部分腾讯游戏学院的相关技术文章内容,感谢原作者的分享. 1.前言 以现在主流的即时通讯应用形态来讲,一个完整的即时通讯IM应用其实是即时通信(英文简写:IM=Instant messaging)和实时通信(英文简写:RTC=Real-time communication)2种技术组合在一起的一整套网络通信系统.之所以以IM这个简写代称整个即时通讯软件,其实是历史原因了(因为早期的诸如ICQ这样的即时通讯工具,也就是文字聊天,并没有加入实时音视频这样的实时通信技术),对这个话题有兴

深入理解多线程(二)—— Java的对象模型

上一篇文章中简单介绍过synchronized关键字的方式,其中,同步代码块使用monitorenter和monitorexit两个指令实现,同步方法使用ACC_SYNCHRONIZED标记符实现.后面几篇文章会从JVM源码的角度更加深入,层层剥开synchronized的面纱. 在进入正题之前,肯定有些基础知识需要铺垫,那么先来看一下一个容易被忽略的但是又很重要的知识点 -- Java对象模型 . 大家都知道的是,Java对象保存在堆内存中.在内存中,一个Java对象包含三部分:对象头.实例数

深入理解JVM虚拟机4:Java class介绍与解析实践

微信公众号[Java技术江湖]一位阿里 Java 工程师的技术小站.作者黄小斜,专注 Java 相关技术:SSM.SpringBoot.MySQL.分布式.中间件.集群.Linux.网络.多线程,偶尔讲点Docker.ELK,同时也分享技术干货和学习经验,致力于Java全栈开发!(关注公众号后回复”Java“即可领取 Java基础.进阶.项目和架构师等免费学习资料,更有数据库.分布式.微服务等热门技术学习视频,内容丰富,兼顾原理和实践,另外也将赠送作者原创的Java学习指南.Java程序员面试指

JAVA之IO技术-将java程序的异常信息保存在文件中

package ioTest.io2; import java.io.FileNotFoundException; import java.io.PrintStream; import java.util.Properties; /* * 将应用程序的异常信息输出到指定的log文件中 */ public class ExceptionToFile { public static void main(String[] args) throws FileNotFoundException { int

关于java同步包中ConcurrentLinkedQueue类的深入分析与理解

一,官方描述 一个基于连接节点的无界线程安全队列.这个队列的顺序是先进先出.队列头部的元素是留在队列中时间最长的,队列尾部的元素是留在队列中时间最短的.新元素被插入到元素的尾部,队列从队列的头部检索元素.当许多线程共享访问同一个集合时,这个类是不二选择.这个队列不允许有null元素. 这个实现基于一种被描述为简单,快速,实用的非阻塞和阻塞公布队列算法而提供的一种有效的空闲等待算法. 注意,不像大多数集合,size方法的操作不是常量时间的,由于是异步队列,决定了元素的数量需要遍历真个元素集. 这个

深入理解Linux网络技术内幕——IPv4 报文的传输发送

报文传输,指的是报文离开本机,发往其他系统的过程. 传输可以由L4层协议发起,也可以由报文转发发起. 在深入理解Linux网络技术内幕--IPv4 报文的接收(转发与本地传递)一文中,我们可以看到,报文转发最后会调用dst_output与邻居子系统进行交互,然后传给设备驱动程序. 这里,我们从L4层协议发起的传输,最后也会经历这一过程(调用dst_output).本文讨论的是L4层协议发起的传输,在IPv4协议处理(IP层)中的一些环节. 大蓝图 我们先看下传输环节的大蓝图,以便对传输这一过程有

Java技术与Java虚拟机

Java技术与Java虚拟机 说起Java,人们首先想到的是Java编程语言,然而事实上,Java是一种技术,它由四方面组成:Java编程语言.Java类文件格式.Java虚拟机和Java应用程序接口(Java API).它们的关系如下图所示: 图1 Java四个方面的关系 运行期环境代表着Java平台,开发人员编写Java代码(.java文件),然后将之编译成字节码(.class文件).最后字节码被装入内存,一旦字节码进入虚拟机,它就会被解释器解释执行,或者是被即时代码发生器有选择的转换成机器