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里。
    代码演进之后,对象的产生的控制权转移到配置文件里。
    这就是控制(权)反转的解释了。

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

  • 相关阅读:
    Centos7.2安装MariaDB数据库,并进行基础配置
    Web安全之环境搭建
    PHP构建一句话木马
    Spark2.1.0安装
    Spark2.1.0编译
    cdh-5.10.0搭建安装
    八、频繁模式挖掘Frequent Pattern Mining
    七、特征提取和转换
    六、降维
    五、聚类
  • 原文地址:https://www.cnblogs.com/cyq1162/p/3120231.html
Copyright © 2011-2022 走看看