一步一步造个IoC轮子(二),详解泛型工厂
2016-06-29 20:56 BlackMagic# 阅读(3790) 评论(5) 编辑 收藏 举报一步一步造个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的可以直接复制代码出来