zoukankan      html  css  js  c++  java
  • 一步一步造个IoC轮子(二),详解泛型工厂

    一步一步造个Ioc轮子目录

    一步一步造个IoC轮子(一):Ioc是什么
    一步一步造个IoC轮子(二):详解泛型工厂
    一步一步造个IoC轮子(三):构造基本的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的可以直接复制代码出来

  • 相关阅读:
    更改套接字I/O缓冲大小
    读取创建套接字时默认IO缓冲大小
    利用getsockopt读取套接字可选项
    如何查看安装的ubuntu是多少位的系统
    使用虚函数所带来的扩展性
    python学习第17天----接口类/抽象类、多态、封装
    python学习第16天----继承、查找顺序(深度、广度优先)
    python学习第15天----名称空间、组合
    python学习第14天----函数复习、面向对象初始
    python学习第13天----lambda、sorted、map、filter、递归、二分查找
  • 原文地址:https://www.cnblogs.com/life2009/p/ioc2.html
Copyright © 2011-2022 走看看