一步一步造个Ioc轮子(二),详解泛型工厂

一步一步造个Ioc轮子目录

.net core发布了,一步一步造个Ioc轮子,弄点.net魔法,近new的速度(一)
一步一步造个Ioc轮子(二),详解泛型工厂

详解泛型工厂

既然我说Ioc容器就是一个豪华版工厂,自动化装配的工厂,那我们就从工厂入手吧,先造个工厂,然后升级成Ioc容器

首先我们来写一个最最最简单的抽象工厂类,还是以前一篇的短信为例

    public class SMSFactory
    {
        public static ISMS Get()
        {
            return new XSMS();
        }
    }

然后我们琢磨着怎么把这个XSMS不要写死在代码上,嗯加一个注册方法,把SMS对象传进去

    public class SMSFactory
    {
        static ISMS _sms;
        public static ISMS Get()
        {
            return _sms;
        }
        public static void Reg(ISMS sms)
        {
            _sms = sms;
        }
    }

这个代码分离了业务对XSMS的依赖,但依然要在程序启动时注册一个ISMS实现对象进去如:SMSFactory.Reg(new XSMS());

我们再琢磨着这个工厂越写越复杂,还只能用来做短信,能不能搞成通用呢,嗯,改成泛型吧

    public class Factory<T> where T:class
    {
        static T _obj;
        public static T Get()
        {
            return _obj;
        }
        public static void Reg(T obj)
        {
            _obj = obj;
        }
    }

嗯,搞出一个好简单的泛型工厂了,我们再琢磨一下,这东西要在系统启动就传new好的对象进去,有点不科学啊,能不能让工厂自己new 呢,试试吧

    public class Factory<T> where T:class,new()
    {
        public static T Get()
        {
            return new S();  //晕了,S的从哪里取呢
        }
        public static void Reg<S>() where S:T
        {
            //怎么把S(继承类)保存下来呢???这下头痛了
        }
    }

貌似不行哦,我们怎么保存继承类的信息在这个工厂里呢,聪明的前人想到了一个方法,用一个含S信息的对象创建不就行了,这个对象又继承了一个含Create方法的接口,Get的时候调用这个对象的Create的方法

    public class Factory<T> where T : class
    {
        static ICreate creater;
        interface ICreate
        {
            T Create();
        }
        class Creater<U> : ICreate where U : T, new()
        {
            public T Create()
            {
                return new U();
            }
        }
        public static T Get()
        {
            //调用creater对象的Create方法实际上相当于调用了Creater<U>的new U()
            return creater.Create();
        }
        public static void Reg<S>() where S : T, new()
        {
            //在这里,我们把S的信息保存到了creater对象上
            creater = new Creater<S>();
        }
    }

完美啊,用一个临时的对象保存了继承类的信息,这样就可以在工厂类注册继承类进去了,回到上篇小黄的改来改去的SMS模块问题,我们也可以用这个泛型工厂解决掉业务的依赖问题了var sms = Factory<ISMS>.Get();只是要在启动的配置里注册上实现类

我们能不能再扩展一下,让他支持单例呢,答案当然是yes了,只要对Creater改造一下

    public class Factory<T> where T : class
    {
        static ICreate creater;
        interface ICreate
        {
            T Create();
        }
        class Creater<U> : ICreate where U : T, new()
        {
            public T Create()
            {
                return new U();
            }
        }
        class SingletonCreater<U> : ICreate where U : T, new()
        {
            T instance;
            object locker = new object();
            public T Create()
            {
                //使用双检锁
                if (instance == null)
                {
                    lock (locker)
                    {
                        if (instance == null)
                        {
                            Interlocked.Exchange(ref instance, new U());
                        }
                    }
                }
                return instance;
            }
        }
        public static T Get()
        {
            return creater.Create();
        }
        public static void Reg<S>() where S : T, new()
        {
            creater = new Creater<S>();
        }
        public static void RegSingleton<S>() where S : T, new()
        {
            creater = new SingletonCreater<S>();
        }
    }

哟,真行,不过有锁,能不能去掉锁呢,yes,我们来用静态readonly魔法,创建一个内部类,只有访问这个内部类时这个对象才会被创建,而且是线程安全的

    public class Factory<T> where T : class
    {
        static ICreate creater;
        interface ICreate
        {
            T Create();
        }
        class Creater<U> : ICreate where U : T, new()
        {
            public T Create()
            {
                return new U();
            }
        }
        class SingletonCreater<U> : ICreate where U : T, new()
        {
            class InstanceClass
            {
                public static readonly T Instance = new U();
            }
            public T Create()
            {
                return InstanceClass.Instance;
            }
        }
        public static T Get()
        {
            return creater.Create();
        }
        public static void Reg<S>() where S : T, new()
        {
            creater = new Creater<S>();
        }
        public static void RegSingleton<S>() where S : T, new()
        {
            creater = new SingletonCreater<S>();
        }
    }

果然黑魔法,接下来我们再魔改一下这个泛型工厂,让他支持传入参数,其实也很简单,用个字典保存一下key和creater的对应关系就是了

    public class Factory<T> where T : class
    {
        interface ICreate
        {
            T Create();
        }
        class Creater<U> : ICreate where U : T, new()
        {
            public T Create()
            {
                return new U();
            }
        }
        class SingletonCreater<U> : ICreate where U : T, new()
        {
            class InstanceClass
            {
                public static readonly T Instance = new U();
            }
            public T Create()
            {
                return InstanceClass.Instance;
            }
        }
        #region 无参数的
        static ICreate creater;
        public static T Get()
        {
            return creater.Create();
        }
        public static void Reg<S>() where S : T, new()
        {
            creater = new Creater<S>();
        }
        public static void RegSingleton<S>() where S : T, new()
        {
            creater = new SingletonCreater<S>();
        }
        #endregion

        #region 有参数的
        static IDictionary<string, ICreate> creaters = new System.Collections.Concurrent.ConcurrentDictionary<string, ICreate>();
        public static T Get(string key)
        {
            ICreate ct;
            if (creaters.TryGetValue(key, out ct))
                return ct.Create();
            throw new Exception("未注册");
        }
        public static void Reg<S>(string key) where S : T, new()
        {
            creaters[key] = new Creater<S>();
        }
        public static void RegSingleton<S>(string key) where S : T, new()
        {
            creaters[key] = new SingletonCreater<S>();
        }
        #endregion
    }

好了,泛型工厂详解和魔改完毕,支持注册单例,测试一下,完美,是不是已经有了Ioc的味道了,下一步我们就再魔改这个工厂,改造为可以从配置读取及优化从参数的获取的性能



我不是想引起战争,但真泛型确是.net的魔法,java这样搞是不行的,java只能反射了,接近new的性能就是.net真泛型所赋予的

代码下载,用VS2015 update3写的,不用.net core的可以直接复制代码出来

时间: 2024-08-02 06:59:47

一步一步造个Ioc轮子(二),详解泛型工厂的相关文章

一步一步造个IoC轮子(三):构造基本的IoC容器

一步一步造个Ioc轮子目录 一步一步造个IoC轮子(一):Ioc是什么 一步一步造个IoC轮子(二):详解泛型工厂 一步一步造个IoC轮子(三):构造基本的IoC容器 定义容器 首先,我们来画个大饼,定义好构造函数,注册函数及获取函数这几个最基本的使用方法 /// <summary> /// IoC容器 /// </summary> public class Container { /// <summary> /// 构造函数 /// </summary>

一步一步学会puppet(五)--配置文件和常用命令详解

这篇博文主要解析了puppet的配置文件和常用命令,以备以后查阅: =================================================================== 1 配置文件 1.1 组织结构 2 常用命令 2.1 常用命令 2.2 各类命令详解 2.3 帮助类命令 =================================================================== 1 配置文件 1.1 组织结构 配置文件位于/etc/

Spring IOC源码详解之容器初始化

Spring IOC源码详解之容器初始化 上篇介绍了Spring IOC的大致体系类图,先来看一段简短的代码,使用IOC比较典型的代码 ClassPathResource res = new ClassPathResource("beans.xml"); DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); XmlBeanDefinitionReader reader = new XmlBeanDe

Spring IOC源码详解之容器依赖注入

Spring IOC源码详解之容器依赖注入 上一篇博客中介绍了IOC容器的初始化,通过源码分析大致了解了IOC容器初始化的一些知识,先简单回顾下上篇的内容 载入bean定义文件的过程,这个过程是通过BeanDefinitionReader来完成的,其中通过 loadBeanDefinition()来对定义文件进行解析和根据Spring定义的bean规则进行处理 - 事实上和Spring定义的bean规则相关的处理是在BeanDefinitionParserDelegate中完成的,完成这个处理需

.net core发布了,一步一步造个Ioc轮子,弄点.net魔法,近new的速度(一)

前言 .net core正式版前两天发布了,喜大普奔,借此机会,强行来写第一篇博客 第一次写博客,有点紧张,不知怎么才能装做经常写的样子(: 第一次,造个小轮子吧,Ioc容器,借此完善自己的类库 DI,Ioc什么的高大上的名字是什么意思 我不是老司机,开C#时间不太长,以下粗浅个人见解,说错了打脸要轻一点,毕竟是还想靠脸吃饭 (: 怕词不达意,用个示例来说明吧,老司机绕行 小黄是一家电商公司的主程,有一天老板说我们加个发货短信通知发短信给客户吧 于是小黄找了一个叫XSMS的短信通道供应商签约了

【框架】[Spring3]下载安装、开源框架与IoC控制反转详解

转载请注明出处:http://blog.csdn.net/qq_26525215 本文源自[大学之旅_谙忆的博客] 昨天刚刚初学Spring3,也许Spring3有点老了哈,不过还是先把3学了再去学习4吧,首先先介绍一下如何去下载Spring的必须包吧. (本篇博客适用于初学Spring的朋友) java spring4现在不推荐使用xml配置文件- 当然啦,这些知识点在Spring4还是可以用的. 不过我在这里详解的还是Spring3哈,见谅~ 下载SpringJAR包/文档: Spring官

Spring IOC源码详解之总体结构

Spring ICO详解之总体结构 IOC介绍 IOC, spring的核心,贯穿Spring始终.直观的来说,就是由spring来负责控制对象的生命周期和对象间的关系,将对象之间的关系抽象出来,通过spring容器控制对象生成时机,减少对象之间的耦合度. 开启Spring IOC源码学习 SpringIOC 的主要依赖源码是 spring-beans 和 spring-context两个包.前面文章中曾今讲到了如何编译spring源码,接下来将maven后的工程导入eclipse里面. 一.s

Spring之IOC核心模块详解

Spring IOC简述 IOC称为控制反转,也有一种说法叫DI(依赖注入).IOC也是spring最核心的模块,Spring的所有工作几乎都围绕着IOC展开. 什么是控制反转呢?简单的说,控制反转就是把我们要做的事情交给别人来做,就像是招了个小弟专门为我们做事情,我们需要做好的东西时直接去找小弟拿. 这里要做的事情就是new 一个对象.我们不再自己去new对象然后使用,而是spring容器帮我们去创建对象然后我们要用的时候直接去拿就行了.spring帮我们 生成对象就是控制反转,而我们要用对象

c# winform控件dock属性停造位置、摆放顺序详解

dock : [英文释义- 码头.依靠][winform释义- 获取或设置当前控件依靠到父容器的哪一个边缘.] 用途:多数控件都有这个属性,主要用来设置控件的布局. 但对于不太了解这个属性的朋友来说有时候会遇到比较头疼的问题: 简单的布局就是摆放不好,达不到预定的效果.出现这种问题往往是忽略了Dock的一个特性“控件依照 Z 顺序停靠. 什么是Z 顺序呢?MSDN里有这么一段描述: Z 顺序是窗体上的控件沿窗体的 Z-轴(深度)方向的可视化分层. 也就是说控件是“一层一层摞放在窗体上的”,离窗体