一步一步造个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. 【u223】放牙刷

    [题目链接]: [题解] 错排公式 f[n] = (n-1)*(f[n-1]+f[n-2]); 这样理解: 要从n-1和n-2递推到n; 假设第n个位置上的数要放在前n-1个位置中的k位置;则有n-1 ...

  2. [Java][web]利用Spring随时随地获得Request和Session

    利用Spring随时随地获得Request和Session 一.准备工作: 在web.xml中加入 <listener> <listener-class> org.spring ...

  3. C++对象模型——对象成员的效率 (Object Member Efficiency)(第三章)

    3.5 对象成员的效率 (Object Mem ber Efficiency) 以下某个測试,目的在測试聚合(aggregation).封装(encapsulation),以及继承(Inheritan ...

  4. vi/vim基本使用命令

    vi/vim基本使用命令 一.总结 一句话总结:1.记住三种模式:命令行模式.插入模式.底行模式:2.记住两个按键功能:i和esc 二.vi/vim基本使用命令 vi/vim 基本使用方法本文介绍了v ...

  5. js进阶 9-5 js如何确认form的提交和重置按钮

    js进阶 9-5 js如何确认form的提交和重置按钮 一.总结 一句话总结: 1.这个并不好做:onsubmit 里面的代码必须返回false才能取消onsubmit方法的执行,所以,有return ...

  6. activity-alias详解及应用

    activity-alias标签元素众所周知,AndroidManifest是一个xml文件,它包含很多标签元素,如application.activity.receiver等,其中有一个叫做acti ...

  7. CentOS 配置epel源

    先查询下有没有epel rpm -qa|grep epel 没有的话到官网https://fedoraproject.org/wiki/EPEL下载rpm包 然后 rpm -ivh 安装 安装完毕后到 ...

  8. unityd 公布android apk相关

    http://game.ceeger.com/forum/read.php?tid=5918&ds=1 相关的文章非常多,我仅仅记录自己遇到的一些关键点. 1.jdk android SDK ...

  9. MySQL日期 专题

    一.MySQL 获得当前日期时间 函数 1.1 获得当前日期+时间(date + time)函数:now() mysql> select now();+--------------------- ...

  10. 【29.82%】【codeforces 703D】Mishka and Interesting sum

    [题解] 题意: 给n个数字组成有序数列; 给m个询问. 对于每个询问区间.输出这个区间里面出现次数为偶数次的所有数的异或值; 做法: 我们可以先求出这段区间里面所有(包括重复的数字)数字的异或值p1 ...