通过 人打电话 来谈谈自己对IOC的理解

版本1.0

    public class Person
    {
        public AndroidPhone Phone { get; set; }

        public void CallForSomebody()
        {
            Phone.Call();
        }
    }

    public class AndroidPhone
    {
        public void Call()
        {
            Console.WriteLine($"{this.GetType().Name} is calling");
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Person person = new Person
            {
                Phone = new AndroidPhone()
            };
            person.CallForSomebody();
            Console.ReadKey();
        }
    }

如果这时候,想给这个人一部苹果手机,那么必须要修改 Person 类, 将属性Phone的类型改成:ApplePhone.这显然违背了OOP思想的"对修改封闭,对扩展开放"原则.同时该代码也不符合"接口分离原则",于是乎做如下调整.

版本2.0

    public class Person
    {
        //定义 Phone 为 接口 IPhone 类型
        public IPhone Phone { get; set; }

        public void CallForSomebody()
        {
            Phone.Call();
        }
    }

    public interface IPhone
    {
        void Call();
    }

    public class ApplePhone : IPhone
    {
        public void Call()
        {
            Console.WriteLine($"{this.GetType().Name} is calling");
        }
    }

    public class AndroidPhone : IPhone
    {
        public void Call()
        {
            Console.WriteLine($"{this.GetType().Name} is calling");
        }
    }

控制台程序:
            Person person = new Person();

            //给这个人一部安卓手机
            person.Phone = new AndroidPhone();
            person.CallForSomebody();

            //给这个人一部苹果手机
            person.Phone = new ApplePhone();
            person.CallForSomebody();

如果需要给诺基亚手机,只需要在创建一个诺基亚Phone类,实现  IPhone 接口,而不需要修改底层代码.

依赖注入有三种方式:

    public class Person
    {
        //属性注入
        public IPhone Phone { get; set; }

        //构造函数注入
        public Person(IPhone phone)
        {
            this.Phone = phone;
        }

        //方法注入
        public void MethodInject(IPhone phone)
        {
            this.Phone = phone;
        }

        public void CallForSomebody()
        {
            Phone.Call();
        }
    }

版本2.0虽然不需要修改底层代码,但是控制台的代码依然需要修改,我们需要将 new AndridPhone() 更改成 new ApplePhone()

版本3.0 ( 利用 Unity )

学习新东西都是从 hello world 开始,先来一段 Unity 的 hello world

            //创建一个IOC容器
            IUnityContainer container = new UnityContainer();

            //想要安卓手机就注册安卓手机
            //container.RegisterType<IPhone, AndroidPhone>();

            //想要苹果手机就注册苹果手机
            container.RegisterType<IPhone, ApplePhone>();

            IPhone phone = container.Resolve<IPhone>();

            Person person = new Person(phone);
            person.CallForSomebody();

这段代码其实 跟 版本2.0没什么区别,甚至还复杂了,版本2.0是改 new AndroidPhone() ,  这里是改  container.RegisterType<IPhone, AndroidPhone>()

版本4.0

新建一个配置文件:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>

  <configSections>
    <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,Microsoft.Practices.Unity.Configuration"/>
  </configSections>

  <unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
    <containers>
      <container name="unityContainer">
        <!--type,mapTo:逗号左边是类的完全限定名,即命名空间+类名;逗号右边是程序集名称-->
        <register type="IOCUnity.IPhone,IOCUnity" mapTo="IOCUnity.AndroidPhone,IOCUnity"></register>
      </container>
    </containers>
  </unity>

</configuration>

控制台代码如下:

            ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap
            {
                ExeConfigFilename = Path.Combine(AppDomain.CurrentDomain.BaseDirectory + @"UnityXml\UnityConfig.xml")
            };
            Configuration configuration = ConfigurationManager.OpenMappedExeConfiguration(fileMap,ConfigurationUserLevel.None);
            UnityConfigurationSection section = (UnityConfigurationSection)configuration.GetSection(UnityConfigurationSection.SectionName);

            IUnityContainer container = new UnityContainer();
            section.Configure(container, "unityContainer");
            IPhone phone = container.Resolve<IPhone>();

            Person person = new Person(phone);
            person.CallForSomebody();

如果要换成 ApplePhone , 只需要将 配置文件中  mapTo="IOCUnity.AndroidPhone,IOCUnity" 更改成 mapTo="IOCUnity.ApplePhone,IOCUnity"> 即可,源代码不需要做任何修改

版本4.5

配置文件修改: 添加 name 标记

        <register type="IOCUnity.IPhone,IOCUnity" mapTo="IOCUnity.ApplePhone,IOCUnity" name="Apple"></register>
        <register type="IOCUnity.IPhone,IOCUnity" mapTo="IOCUnity.AndroidPhone,IOCUnity" name="Android"></register>
            //创建一个安卓手机
            //IPhone phone = container.Resolve<IPhone>("Android");

            //创建一个苹果手机
            IPhone phone = container.Resolve<IPhone>("Android");

版本5.0

控制台代码:

            ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap
            {
                ExeConfigFilename = Path.Combine(AppDomain.CurrentDomain.BaseDirectory + @"UnityXml\UnityConfig.xml")
            };
            Configuration configuration = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);
            UnityConfigurationSection section = (UnityConfigurationSection)configuration.GetSection(UnityConfigurationSection.SectionName);

            IUnityContainer container = new UnityContainer();
            section.Configure(container, "unityContainer");

            Person person = container.Resolve<Person>();
            /*
            上面创建了一个person,虽然我们没有给它的属性Phone赋值,但实际上 Unity 已经帮我们注入了.
            Unity 有三种特性 分别对应三种注入方式:
            [InjectionConstructor] 构造函数注入
            [dependency]           属性注入
            [InjectionMethod]      方法注入
            如果一个特性都不打,那么Unity 默认会采用 构造函数注入,并且是选用入参最多的那个构造函数注入.因此,推荐采用 构造函数注入,因为它是无侵入式的,不需要打任何特性.
             */
            person.CallForSomebody();
    public class Person
    {

        //属性注入
        [Dependency]
        public IPhone Phone { get; set; }

        //构造函数注入
        [InjectionConstructor]
        public Person(IPhone phone)
        {
            this.Phone = phone;
        }

        //方法注入
        [InjectionMethod]
        public void MethodInject(IPhone phone)
        {
            this.Phone = phone;
        }

        public void CallForSomebody()
        {
            Phone.Call();
        }
    }
<?xml version="1.0" encoding="utf-8" ?>
<configuration>

  <configSections>
    <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,Microsoft.Practices.Unity.Configuration"/>
  </configSections>

  <unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
    <containers>
      <container name="unityContainer">
        <!--type,mapTo:逗号左边是类的完全限定名,即命名空间+类名;逗号右边是程序集名称-->
        <register type="IOCUnity.IPhone,IOCUnity" mapTo="IOCUnity.ApplePhone,IOCUnity"></register>
        <register type="IOCUnity.Person,IOCUnity" mapTo="IOCUnity.Person,IOCUnity"></register>
      </container>
    </containers>
  </unity>

</configuration>

C# 一个初学者对 依赖注入 IOC 的理解( 含 Unity 的使用)的更多相关文章

  1. 控制反转(Inversion of Control,英文缩写为IoC),另外一个名字叫做依赖注入(Dependency Injection,简称DI)

    控制反转(Inversion of Control,英文缩写为IoC),另外一个名字叫做依赖注入(Dependency Injection,简称DI),是一个重要的面向对象编程的法则来削减计算机程序的 ...

  2. android使用篇(四) 注解依赖注入IOC实现绑定控件

    在android使用篇(三) MVC模式中提到一个问题: 1) 视图层(View):一般採用XML文件进行界面的描写叙述,使用的时候能够很方便的引入,可是用xml编写了,又须要在Acitvity声明而 ...

  3. 从壹开始前后端分离【 .NET Core2.0 +Vue2.0 】框架之九 || 依赖注入IoC学习 + AOP界面编程初探

    更新 1.如果看不懂本文,或者比较困难,先别着急问问题,我单写了一个关于依赖注入的小Demo,可以下载看看,多思考思考注入的原理: https://github.com/anjoy8/BlogArti ...

  4. Z从壹开始前后端分离【 .NET Core2.2/3.0 +Vue2.0 】框架之九 || 依赖注入IoC学习 + AOP界面编程初探

    本文梯子 本文3.0版本文章 更新 代码已上传Github+Gitee,文末有地址 零.今天完成的绿色部分 一.依赖注入的理解和思考 二.常见的IoC框架有哪些 1.Autofac+原生 2.三种注入 ...

  5. TypeC一个微软开发的超简单.NET依赖注入/IoC容器

    控制反转(IoC,Inversion of Control)是由Martin Fowler总结出来的一种设计模式,用来减少代码间的耦合.一般而言,控制反转分为依赖注入(Dependency Injec ...

  6. 关于依赖注入IOC/DI的感想

    之前一直不明白依赖注入有什么好处,甚至觉得它是鸡肋,现在想想,当时真是可笑. 这个想法正如同说接口是没有用处一样. 当整个项目非常庞大,各个方法之间的调用非常复杂,那么,可以想象一下,假设说没有任何的 ...

  7. DI依赖注入/IOC控制反转

    DI依赖注入# 啥都不说,直接上代码 <?php class UserController { private $user; function __construct(UserModel $us ...

  8. 大话DI依赖注入+IOC控制反转(二) 之 浅析.Net Core中的DI与IOC

      转发时请注明原创作者及地址,否则追究责任.原创:alunchen 在上一篇文章中,我们聊了很多关于定义的方面,比较孤燥,下面我们结合.Net Core聊一下依赖注入&控制反转. 三种对象生 ...

  9. 大话DI依赖注入+IOC控制反转(一) 之 定义

    转发时请注明原创作者及地址,否则追究责任.原创:alunchen 依赖注入与控制反转      依赖注入与控制反转是老生常谈的问题.一般面试也会面试到这种问题.网上很多很多这方面的资料,搜索出来一大堆 ...

随机推荐

  1. javaweb 关于页面获取数据

    EL(Excepress Language表达式语言) 1.....所有的EL都是以$"{"开始,以"}"结尾的.例:${sessionScope.user.s ...

  2. Lintcode212 Space Replacement solution 题解

    [题目描述] Write a method to replace all spaces in a string with%20. The string is given in a characters ...

  3. 去除IE10自带的清除按钮

    最近在工作中碰到了一个问题,原本在IE8,IE9下正常的input表单,在IE10下会出现清除按钮,即表单右侧会出现一个可以清除该表单内容的小叉.由于之前一直没有兼容过IE10,所以我专门搜了下原因. ...

  4. 发个2012年用java写的一个控制台小游戏

    时间是把杀狗刀 突然发现了12年用java写的控制台玩的一个文字游戏,有兴趣的可以下载试试哈汪~ 里面难点当时确实遇到过,在计算倒计时的时候用了多线程,当时还写了好久才搞定.很怀念那个时间虽然不会做游 ...

  5. git远程提交失败

    同步仓库并解决403报错 这时候对本地仓库和github进行同步 # git push -u origin master error: The requested URL returned error ...

  6. freemarker的classic_compatible设置,解决报空错误

    前段时间接触freemaker时,本来后端写各接口运行正常,但加入了模板后,频繁报空指针问题,整了许久,最后还是请教了别人解决了这个问题,现在记录下来,方便以后碰到了可以查阅. 错误样例如下: ERR ...

  7. 初始化angularJS之ng-app的自动绑定和手动绑定

    在传统的angularJS应用中,都是通过ng-app把angular应用绑定到某个dom上,这样做会把js代码入侵到html上,angular提供了手动启动的API--angular.bootstr ...

  8. 【Flask】 网站的用户管理

    网站用户管理 不知道为什么很多学习Flask的人都是从搭博客开始的(大概是因为那本书的案例是博客,同时对bootstrap支持良好,bootstrap又是twitter开发的吧..)既然是搭建博客,就 ...

  9. 多线程 Synchronized关键字和Lock

    Synchronized  分为实例锁和全局锁. 实例锁为 synchronized(this) 和 非static synchronized方法.   也加对象锁. 只要一个线程访问这类的一个syn ...

  10. Oracle 琐表和查询谁在琐表并解决

    Oracle数据库操作中,我们有时会用到锁表查询以及解锁和kill进程等操作,那么这些操作是怎么实现的呢?本文我们主要就介绍一下这部分内容. (1)锁表查询的代码有以下的形式: select coun ...