zoukankan      html  css  js  c++  java
  • 傻嘎,IOC原来是这样子的

    昨天有网友Call我留言,说他写了个DI架构,让我有时间看看,于是我就上去看了:

    文章地址: http://www.cnblogs.com/lenic/archive/2013/06/04/3117893.html

    发现是E文的,于是回复:

    路过秋天 22:32:43 
    怎么还写E文的
    NOoK 22:33:03 
    直接在 CodePlex 上写的介绍
    NOoK 22:33:08 
    然后就粘过来了
    NOoK 22:33:15 
    结果还被博客园下架了。。。
    NOoK 22:34:40 
    悲催的
    路过秋天 22:35:34 
    谁让你 Look it on CodePlex
    NOoK 22:35:41 
    。。。 

    我错了 

    接着他让我下载他的处女开源项目,让我看看:

    NOoK 22:36:09 
    明天再修改一下吧
    路过秋天 22:37:26 
    平时都习惯写英文?
    NOoK 22:37:40 
    肯定不是啊
    NOoK 22:38:03 
    在 CodePlex 上面写了,懒得改就贴过来了
    路过秋天 22:38:43 
    平时也在CodePlex上面写?
    NOoK 22:38:54 
    第一个开源项目。。。
    NOoK 22:40:35 
    改好了再说吧
    路过秋天 22:40:46 
     
    NOoK 22:41:14 
    你可以下载代码看看,维护了好几年了
    路过秋天 22:43:17 
    Ok,我看看
    路过秋天 22:48:23 
    扫了一下,不是很理解
    NOoK 22:50:15 
    思路是,注册委托进字典,需要的时候,再用委托生成对象
    NOoK 22:50:41 
    然后衍生了多个生存周期;
    路过秋天 22:50:50 
    实用场景 ?
    NOoK 22:51:42 
    一样啊
    NOoK 22:51:56 
    就是IOC的使用场景
    NOoK 22:52:46 
    这个核心代码,类似于Ninject,没配置 


    由于本人对IOC,虽然曾多次看过网上的文章介绍,除了“依赖注入,控制反转”这八个字,没有多余的存档记忆了。

    后来的聊天,我让他给我举一个实用场景,毕竟我是实战派的,一种模式或一种东东,只有摆在现实的场景,并且有过深刻的使用痕迹,才能记的深,用的劳。

    像那些设计模式的文章,一来就是UML图,举个例子基本就是猫和狗,要不就是会飞的鸭子。
    费我十八层脑力,终于理解明白了。
    第二天一睡醒,基本没印象。
    再过些天。。。连设计模式的名字都不知叫什么了。


    后来中间拧了一阵,基本没拧在一块,我要的是实战场景,他老给我讲理论。

    于是我就迁就他学理论了,我搜索看了看IOC的的基本介绍:

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

    早在2004年,Martin Fowler就提出了“哪些方面的控制被反转了?”这个问题。他总结出是依赖对象的获得被反转了。基于这个结论,他为控制反转创造了一个更好的名字:依赖注入。许多非凡的应用(比HelloWorld.java更加优美,更加复杂)都是由两个或是更多的类通过彼此的合作来实现业务逻辑,这使得每个对象都需要,与其合作的对象(也就是它所依赖的对象)的引用。如果这个获取过程要靠自身实现,那么如你所见,这将导致代码高度耦合并且难以测试。
    IoC 亦称为 “依赖倒置原理”("Dependency Inversion Principle")。差不多所有框架都使用了“倒置注入(Fowler 2004)技巧,这可说是IoC原理的一项应用。SmallTalk,C++, Java 或各种.NET 语言等面向对象程序语言的程序员已使用了这些原理。
    控制反转是Spring框架的核心。
    应用控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体,将其所依赖的对象的引用,传递给它。也可以说,依赖被注入到对象中。所以,控制反转是,关于一个对象如何获取他所依赖的对象的引用,这个责任的反转。

    oC就是IoC,不是什么技术,与GoF一样,是一种设计模式。

    当然了,资料还有一大堆,就不详细贴了。

    后来他为了拧过我,决定给我培训一下,给我出了道题:

    NOoK 23:30:52 
    要不要做题?
    NOoK 23:31:28 
    一个四则运算的
    路过秋天 23:32:06 
    说说看
    NOoK 23:32:06 
    好吧,我睡觉了,晚安咯
    NOoK 23:33:30 
    通过不同的配置,加载不同的程序集,实现四则运算
    NOoK 23:34:19 
    输入两个参数,运算得到结果
    NOoK 23:35:01 
    不允许用反射
    路过秋天 23:35:31 
    其它条件呢?
    NOoK 23:35:39 
    没有了
    路过秋天 23:36:33 
    使用程序集,却不允许用反射?
    NOoK 23:36:42 
    我就是想通过两个数字,得到结果,怎么运算我不管,只要给我结果就好
    NOoK 23:37:07 
    你可以写到一个程序集里面
    路过秋天 23:37:28 
    过程就是修改配置?
    NOoK 23:37:29 
    我说错了,加载程序集就是反射
    NOoK 23:37:51 
    哥,你问偏了
    NOoK 23:38:11 
    过程你写好
    NOoK 23:38:34 
    通过配置修改
    路过秋天 23:38:51 
    OK,我try一下
    NOoK 23:39:09 
    我等你消息啊,哈哈

    根据要求,2-3分钟后,我就上图了:

    根据配置,加个switch,解决了,不过既然我们在说IOC,肯定是需要不断演进。

    NOoK 0:02:58 
    如果这里的业务很负责呢
    NOoK 0:03:04 
    不是简单的四则运算
    NOoK 0:03:08 
    你怎么办
    路过秋天 0:03:14 
    很负责?
    NOoK 0:03:43 
    很复杂
    NOoK 0:03:48 
    手误
    路过秋天 0:03:50 
    既然是题目,你就举个场景,我按场景实现
    NOoK 0:04:06 
    你应该写4个类,对不对
    NOoK 0:04:11 
    分别实现四种运算
    NOoK 0:04:21 
    比这样写一个类要好
    NOoK 0:04:28 
    以后扩展就可以再写一个类

    好吧,很复杂的话,要分类就这样了:

    IOC演进
    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.IO;

    namespace ABCD
    {
        class Program
        {
            static void Main(string[] args)
            {
                while (true)
                {
                    Console.Read();
                    int result = GetResult(124);
                    Console.WriteLine(result);
                }
            }
            static int GetResult(int a, int b)
            {
                switch (GetConfig())
                {
                    case "+":
                        return new A().GetResult(a,b);
                    case "-":
                        return new B().GetResult(a, b);
                    case "*":
                        return new C().GetResult(a, b);
                    case "/":
                        return new D().GetResult(a, b);
                }
                return 0;
            }
            static string GetConfig()
            {
                string config = AppDomain.CurrentDomain.BaseDirectory + "config.ini";
                return File.ReadAllText(config);
            }
        }
        public class A
        {
            public int GetResult(int a, int b)
            {
                return a + b;
            }
        }
        public class B
        {
            public int GetResult(int a, int b)
            {
                return a - b;
            }
        }
        public class C
        {
            public int GetResult(int a, int b)
            {
                return a * b;
            }
        }
        public class D
        {
            public int GetResult(int a, int b)
            {
                return a / b;
            }
        }

    刚发过去,就来一句:可以提取一个接口吗

    改了改,代码发过去如下:

    IOC 演进2
    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.IO;

    namespace ABCD
    {
        class Program
        {
            static void Main(string[] args)
            {
                while (true)
                {
                    Console.Read();
                    int result = GetResult(124);
                    Console.WriteLine(result);
                }
            }
            static int GetResult(int a, int b)
            {
                IGetResult iResult = null;
                switch (GetConfig())
                {
                    case "+":
                        iResult = new A();
                        break;
                    case "-":
                        iResult = new B();
                        break;
                    case "*":
                        iResult = new C();
                        break;
                    case "/":
                        iResult = new D();
                        break;
                }
                return iResult.GetResult(a, b);
            }
            static string GetConfig()
            {
                string config = AppDomain.CurrentDomain.BaseDirectory + "config.ini";
                return File.ReadAllText(config);
            }
        }
        public interface IGetResult
        {
            int GetResult(int a, int b);
        }
        public class A : IGetResult
        {
            public int GetResult(int a, int b)
            {
                return a + b;
            }
        }
        public class B : IGetResult
        {
            public int GetResult(int a, int b)
            {
                return a - b;
            }
        }
        public class C : IGetResult
        {
            public int GetResult(int a, int b)
            {
                return a * b;
            }
        }
        public class D : IGetResult
        {
            public int GetResult(int a, int b)
            {
                return a / b;
            }
        }


    四则变五则:

    NOoK 0:11:51 
    我现在要加一个业务
    NOoK 0:12:00 
    逻辑是 (a + b) * a
    NOoK 0:12:07 
    怎么办 

    只是加一个类和修改switch,代码过去如下:

    IOC 演进3
    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.IO;

    namespace ABCD
    {
        class Program
        {
            static void Main(string[] args)
            {
                while (true)
                {
                    Console.Read();
                    int result = GetResult(124);
                    Console.WriteLine(result);
                }
            }
            static int GetResult(int a, int b)
            {
                IGetResult iResult = null;
                switch (GetConfig())
                {
                    case "+":
                        iResult = new A();
                        break;
                    case "-":
                        iResult = new B();
                        break;
                    case "*":
                        iResult = new C();
                        break;
                    case "/":
                        iResult = new D();
                        break;
                    case "+*":
                        iResult = new E();
                        break;
                }
                return iResult.GetResult(a, b);
            }
            static string GetConfig()
            {
                string config = AppDomain.CurrentDomain.BaseDirectory + "config.ini";
                return File.ReadAllText(config);
            }
        }
        public interface IGetResult
        {
            int GetResult(int a, int b);
        }
        public class A : IGetResult
        {
            public int GetResult(int a, int b)
            {
                return a + b;
            }
        }
        public class B : IGetResult
        {
            public int GetResult(int a, int b)
            {
                return a - b;
            }
        }
        public class C : IGetResult
        {
            public int GetResult(int a, int b)
            {
                return a * b;
            }
        }
        public class D : IGetResult
        {
            public int GetResult(int a, int b)
            {
                return a / b;
            }
        }
        public class E : IGetResult
        {
            public int GetResult(int a, int b)
            {
                return (a + b) * a;
            }
        }

    最后的需求,消灭switch

    NOoK 0:15:31 

    NOoK 0:15:37 
    这里能写一个字典吗
    NOoK 0:15:46 
    这不就是键值对吗


    OK,我给出了最终代码:

    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.IO;

    namespace ABCD
    {
        class Program
        {
            static void Main(string[] args)
            {
                while (true)
                {
                    Console.Read();
                    int result = GetResult(124);
                    Console.WriteLine(result);
                }
            }
            static int GetResult(int a, int b)
            {
                IGetResult iResult = null;
                string key = GetConfig();
                iResult = ResultRegList.ResultList[key];
                return iResult.GetResult(a, b);
            }
            static string GetConfig()
            {
                string config = AppDomain.CurrentDomain.BaseDirectory + "config.ini";
                return File.ReadAllText(config);
            }
        }
        public interface IGetResult
        {
            int GetResult(int a, int b);
        }
        public class A : IGetResult
        {
            public int GetResult(int a, int b)
            {
                return a + b;
            }
        }
        public class B : IGetResult
        {
            public int GetResult(int a, int b)
            {
                return a - b;
            }
        }
        public class C : IGetResult
        {
            public int GetResult(int a, int b)
            {
                return a * b;
            }
        }
        public class D : IGetResult
        {
            public int GetResult(int a, int b)
            {
                return a / b;
            }
        }
        public class E : IGetResult
        {
            public int GetResult(int a, int b)
            {
                return (a + b) * a;
            }
        }
        public class ResultRegList
        {
            static Dictionary<string, IGetResult> resultList = new Dictionary<string, IGetResult>(5);

            public static Dictionary<string, IGetResult> ResultList
            {
                get
                {
                    if (resultList.Count == 0)
                    {
                        resultList.Add("+"new A());
                        resultList.Add("-"new B());
                        resultList.Add("*"new C());
                        resultList.Add("/"new D());
                        resultList.Add("+*"new E());
                    }
                    return resultList;
                }
            }


        }
    }

    接下来就是终结理论了:

    NOoK 0:23:45 
    这就是了
    路过秋天 0:24:22 
    这东西写了很多,不过没感觉ioc的存在
    NOoK 0:24:23 
    如果以后再添加逻辑,只要写一个IGetResult接口的实现类,再配置到字典里面,就可以了
    NOoK 0:24:34 
    那个字典,其实就是ioc的雏形
    NOoK 0:24:44 
    IOC说到底,就是这样的一个字典
    NOoK 0:25:03 
    通过一个条件,找到所需的实现类
    NOoK 0:25:09 
    然后用到逻辑上
    NOoK 0:25:12 
    就好了
    NOoK 0:25:27 
    再改进,就是用IOC替换你那个字典了
    路过秋天 0:25:32 
    通过一个条件,找到所需要的实现类,看似更像反射
    NOoK 0:25:40 
    这是反射吗?
    NOoK 0:26:09 
    你看到了吗?
    路过秋天 0:26:11 
    你看我的代码,如果增加一个类,ResultRegList这里还需要再注册
    NOoK 0:26:18 
    是的
    NOoK 0:26:37 
    字典是需要你手工改代码的
    路过秋天 0:26:38 
    只有变更为反射,可以解决
    NOoK 0:26:49 
    IOC就是配置一下就可以了
    NOoK 0:26:54 
    不需要改代码了
    NOoK 0:27:33 
    每种IOC都不一样,最简单的就是你写的这种字典
    NOoK 0:27:38 
    然后加上反射
    NOoK 0:27:42 
    这容易理解
    NOoK 0:27:55 
    但是能用到生产上的IOC容器
    NOoK 0:28:03 
    都做了很多工作的
    路过秋天 0:28:15 
    什么工作呢?
    NOoK 0:28:29 
    比如你可以集成AOP
    NOoK 0:28:47 
    添加一些创建前、创建后的事件


    大体上话就拧到这了,后面也没多拧几句,到了洗洗睡了的时间。

    再回头看这段话,理解了,IOC原来是这样子的:

    可以把IoC模式看做是工厂模式的升华,可以把IoC看作是一个大工厂,只不过这个大工厂里要生成的对象都是在XML文件中给出定义的,然后利用Java 的“反射”编程,根据XML中给出的类名生成相应的对象。从实现来看,IoC是把以前在工厂方法里写死的对象生成代码,改变为由XML文件来定义,也就是把工厂和对象生成这两者独立分隔开来,目的就是提高灵活性和可维护性。


    接下来理解“依赖注入、控制反转”八个字:

    依赖注入:

    首先Program里的switch本来是调用new A()这个对象,经过演进后,变成调用IGetResult接口了。
    所以Program本来是依赖new A()对象,结果被IGetResult接口给插了菊花。
    最终就是Program只调用IGetResult接口,Programe和new A()没有直接依赖关系。
    这就是依赖注入的解释了。

     

    控制反转:

    正常说的,new A()对象,是由Program写死在代码里的了,相当于控制权是在Program里。
    代码演进之后,对象的产生的控制权转移到配置文件里。
    这就是控制(权)反转的解释了。

    文章有点长,不知道你理解了没。

  • 相关阅读:
    windows的80端口被占用时的处理方法
    Ansible自动化运维工具安装与使用实例
    Tomcat的测试网页换成自己项目首页
    LeetCode 219. Contains Duplicate II
    LeetCode Contest 177
    LeetCode 217. Contains Duplicate
    LeetCode 216. Combination Sum III(DFS)
    LeetCode 215. Kth Largest Element in an Array(排序)
    Contest 176 LeetCode 1354. Construct Target Array With Multiple Sums(优先队列,递推)
    Contest 176
  • 原文地址:https://www.cnblogs.com/cyq1162/p/3120231.html
Copyright © 2011-2022 走看看