一步一步造个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的可以直接复制代码出来

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

  1. 一步一步造个IoC轮子(一):IoC是什么

    一步一步造个Ioc轮子目录 一步一步造个IoC轮子(一):IoC是什么 一步一步造个IoC轮子(二):详解泛型工厂 一步一步造个IoC轮子(三):构造基本的IoC容器 前言 .net core正式版前 ...

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

    一步一步造个Ioc轮子目录 一步一步造个IoC轮子(一):Ioc是什么 一步一步造个IoC轮子(二):详解泛型工厂 一步一步造个IoC轮子(三):构造基本的IoC容器 定义容器 首先,我们来画个大饼, ...

  3. Spring框架系列(7) - Spring IOC实现原理详解之IOC初始化流程

    上文,我们看了IOC设计要点和设计结构:紧接着这篇,我们可以看下源码的实现了:Spring如何实现将资源配置(以xml配置为例)通过加载,解析,生成BeanDefination并注册到IoC容器中的. ...

  4. Spring框架系列(8) - Spring IOC实现原理详解之Bean实例化(生命周期,循环依赖等)

    上文,我们看了IOC设计要点和设计结构:以及Spring如何实现将资源配置(以xml配置为例)通过加载,解析,生成BeanDefination并注册到IoC容器中的:容器中存放的是Bean的定义即Be ...

  5. Spring IoC @Autowired 注解详解

    前言 本系列全部基于 Spring 5.2.2.BUILD-SNAPSHOT 版本.因为 Spring 整个体系太过于庞大,所以只会进行关键部分的源码解析. 我们平时使用 Spring 时,想要 依赖 ...

  6. Spring IoC 公共注解详解

    前言 本系列全部基于 Spring 5.2.2.BUILD-SNAPSHOT 版本.因为 Spring 整个体系太过于庞大,所以只会进行关键部分的源码解析. 什么是公共注解?公共注解就是常见的Java ...

  7. Spring框架系列(6) - Spring IOC实现原理详解之IOC体系结构设计

    在对IoC有了初步的认知后,我们开始对IOC的实现原理进行深入理解.本文将帮助你站在设计者的角度去看IOC最顶层的结构设计.@pdai Spring框架系列(6) - Spring IOC实现原理详解 ...

  8. Spring IoC createBean 方法详解

    前言 本篇文章主要分析 Spring IoC 的 createBean() 方法的流程,以及 bean 的生命周期. 下面是一个大致的流程图: 正文 AbstractAutowireCapableBe ...

  9. Spring IoC getBean 方法详解

    前言 本篇文章主要介绍 Spring IoC 容器 getBean() 方法. 下图是一个大致的流程图: 正文 首先定义一个简单的 POJO,如下: public class User { priva ...

随机推荐

  1. jquery平滑滚动页面

    滚动到顶部 $('.scroll_top').click(function(){$('html,body').animate({scrollTop: '0px'}, 800);}); 滚动到指定位置 ...

  2. jsvc 启动java 在linux下的实现原理

    http://blog.csdn.net/raintungli/article/details/8265009 JSVC:http://commons.apache.org/proper/common ...

  3. [Ramda] Convert a QueryString to an Object using Function Composition in Ramda

    In this lesson we'll use a handful of Ramda's utility functions to take a queryString full of name/v ...

  4. 【BZOJ1426】收集邮票 概率DP 论文题 推公式题

    链接: #include <stdio.h> int main() { puts("转载请注明出处[辗转山河弋流歌 by 空灰冰魂]谢谢"); puts("网 ...

  5. Tools:downloading and Building EDK II工具篇:安装/使用EDKII源代码获取/编译工具[2.3]

    Tools:Installing and using the Required Tools for downloading and Building EDK II工具篇:安装/使用EDKII源代码获取 ...

  6. [Angular] @ViewChild and template #refs to get Element Ref

    We can use @ViewChild with component: @ViewChild(AuthMessageComponent) message: AuthMessageComponent ...

  7. erlang与c之间的连接

    http://blog.chinaunix.net/uid-22566367-id-382012.html erlang与c之间的连接参考资料:网络资料作者:Sunny    在Programming ...

  8. jsp与servlet(转)

    一.基本概念 1.1 Servlet Servlet是一种服务器端的Java应用程序,具有独立于平台和协议的特性,可以生成动态的Web页面.它担当客户请求(Web浏览器或其他HTTP客户程序)与服务器 ...

  9. Erlang 转至维基百科

    Erlang(英语发音:/ˈɜrlæŋ/)是一种通用的并行程序设计语言,它由乔·阿姆斯特朗(Joe Armstrong)在瑞典电信设备制造商爱立信所辖的计算机科学研究室开发,目的是创造一种可以应付大规 ...

  10. 【codeforces 777A】Shell Game

    [题目链接]:http://codeforces.com/contest/777/problem/A [题意] 奇数次操作交换1,2位置的东西; 偶数此操作交换2,3位置的东西 给你操作的次数,和最后 ...