一步一步造个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. WP8.1开发:简单的天气预报应用

    今天小梦给大家分享一个简单的天气预报应用源码:调用的是百度API.整个应用都没有什么难点.只是一个简单的网络请求和json数据处理.在WP8.1有小娜的情况下,天气预报应用还有意义吗?我认为还是有点意 ...

  2. Ajax基础与Json应用(一)

    一.Ajax概念 Ajax是异步的javacript和xml 发音: Ajax [ˈeɪˌdʒæks] 二.同步与异步 传统方式(同步):一个请求对应一个回应,他们是同步的,回应不完成,没办法对这个页 ...

  3. Scrapy系列教程(1)------命令行工具

    默认的Scrapy项目结构 在開始对命令行工具以及子命令的探索前,让我们首先了解一下Scrapy的项目的文件夹结构. 尽管能够被改动,但全部的Scrapy项目默认有类似于下边的文件结构: scrapy ...

  4. 一大波Java来袭(四)String类、StringBuilder类、StringBuffer类对照

    本文主要介绍String类.StringBuffer类.StringBuilder类的差别  : 一.概述 (一)String 字符串常量.可是它具有不可变性,就是一旦创建,对它进行的不论什么改动操作 ...

  5. spark 2.0.2 集群搭建

    由于之前已经搭建过hadoop相关环境,现在搭建spark的预备工作只有scala环境了 一,配置scala环境 1.解压tar包后,编辑/etc/profile 2.source /etc/prof ...

  6. 微信小程序之 满意度

    话不多说,我们来看一下效果图: 要实现的效果:点击到第几颗星,就要显示到第几颗星, 接下来直接查看源码: <view class="l-evalbox row"> &l ...

  7. 多域名绑定同一IP地址,Node.js来实现

    本来打算用Nginx来实现,看了一会Nginx的配置,感觉又要费时间学习,就抱着试试看的心在网上搜,是否可以用Node.js来实现. 没想到,竟然搜到了.想试一下,但国内域名备案时间长达一个月,我肯定 ...

  8. 一种基于uCos-II操作系统和lwIP协议栈的IEEE-1588主站以及基于该主站的报文处理方法

    主站以及应用于电力系统的支持IEEE‐1588协议的主时钟(IEEE‐1588主站)的实现方法.该方法是在一个低成本的硬件平台上,借助uCos‐II操作系统和TCP/IP的协议栈,对以太网数据进行了分 ...

  9. Sublime Text3的react代码校验插件

    之前写前端一直用的是jshint做语法检查,但jshint不支持JSX语法,为了在React使用,需要用eslint代替它.六月份的时候为了写React Native,编辑器换过Webstorm和VS ...

  10. 在 Oracle 中新建 SDE 用户

    --1.创建用户(SDE)和密码(SDE) CREATE USER SDE IDENTIFIED BY SDE --2.创建表空间(SDE) CREATE TABLESPACE SDE DATAFIL ...