一步一步造个IoC轮子(一):IoC是什么
一步一步造个Ioc轮子目录
一步一步造个IoC轮子(一):IoC是什么 一步一步造个IoC轮子(二):详解泛型工厂 一步一步造个IoC轮子(三):构造基本的IoC容器前言
.net core正式版前两天发布了,喜大普奔,借此机会,强行来写第一篇博客
第一次写博客,有点紧张,不知怎么才能装做经常写的样子(:
第一次,造个小轮子吧,IoC容器,借此完善自己的类库
DI,IoC什么的高大上的名字是什么意思
我不是老司机,开C#时间不太长,以下粗浅个人见解,说错了打脸要轻一点,毕竟是还想靠脸吃饭 (:
怕词不达意,用个示例来说明吧,老司机绕行
小黄是一家电商公司的主程,有一天老板说我们加个发货短信通知发短信给客户吧
于是小黄找了一个叫XSMS的短信通道供应商签约了
然后小黄写了开始码代码了
首先写一个XSMS的类
public class XSMS
{
private string sign;
public XSMS(string key, string pwd)
{
sign = "什么都有的电商公司";
}
private string FormatTpl(string tpl, string msg, long phoneNumber, string client, string sign)
{
return tpl.Replace("$sign", sign).Replace("$msg", msg).Replace("$client", client);
}
public void Send(string msg, long phone, string client, string tpl)
{
//签名等等把短信发到XSMS公司的接口上
//XXX的复杂发送代码
Console.WriteLine("从XSMS发短信:" + FormatTpl(tpl, msg, phone, client, sign));
}
}
接着,开始写业务调用了
public static void Main(string[] args)
{
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
while (true)
{
SendMsg2Client();
Thread.Sleep( * );
}
}
private static void SendMsg2Client()
{
var cs = GetClient(); if (cs != null && cs.Count > )
{
string tpl = "[$sign]$client您好,$msg";
var sms = new XSMS("", "");
foreach (var c in cs)
{
sms.Send("您订购的充气女友已发货,查收后请爱惜使用", c.Key, c.Value, tpl);
}
}
} private static void SetSend(long phone)
{
//写到数据库标记已经发了短信
} private static Dictionary<long, string> GetClient()
{
//从数据库里取出需要发短信的客户
return new Dictionary<long, string> { { , "群主" } };
}
好了,业务上线了,老板很满意
过了好大半个月,老板找到小黄:小黄啊,我朋友那里发个短信才4.5分一条,你签那个什么通道怎么要6分一条啊,我们改为他公司的接口吧,我给他公司的技术员QQ你,你跟他联系吧
小黄找到老板朋友公司的技术员,让他搞了一个接口用他公司的帐号去发短信,
好了,小黄又开始加班撸代码了
public class FriendSMS
{
private string sign;
public FriendSMS(string key, string pwd)
{
sign = "什么都有的电商公司";
}
private string FormatTpl(string tpl, string msg, long phoneNumber, string client, string sign)
{
return tpl.Replace("$sign", sign).Replace("$msg", msg).Replace("$client", client);
}
public void Send(string msg, long phone, string client, string tpl)
{
//签名等等把短信发到老板朋友公司提供的接口上
//XXX的复杂发送代码
Console.WriteLine("从FriendSMS发短信:" + FormatTpl(tpl, msg, phone, client, sign));
}
}
撸完短信类的代码,再去修改业务类代码
private static void SendMsg2Client()
{
var cs = GetClient(); if (cs != null && cs.Count > )
{
string tpl = "[$sign]$client您好,$msg";
string key = "";//从配置文件或数据库里取得
string pwd = "";//从配置文件或数据库里取得
var sms = new FriendSMS(key, pwd);//改用老板朋友那家公司的接口了
foreach (var c in cs)
{
sms.Send("您订购的充气女友已发货,查收后请爱惜使用", c.Key, c.Value, tpl);
}
}
}
好了,业务上线了,老板满意,就是小黄累了点,给测试为难了一下:你这业务代码都改了,又要我重新测试整个业务了,下班你要请我大保健啊
业务上线一个月,老板把小黄叫到办公室:小黄啊,你写那个短信怎么老是有客户说收不到呢,你写什么垃圾代码啊,这么不稳定
小黄辩道:老板,不关我事了,是你那朋友公司提供那接口老是不稳定,经常把我们的短信吃掉,我跟他们天天对数据,头都大了,我跟他们技术了解过,他们是用阿里大鱼的接口,他们是写了个代理接口给我们用,不如我们直接用阿里大鱼的接口吧,一样是4.5分一条短信,直接对接肯定稳定很多,不会受制于你朋友的公司了
老板:好吧,弄好了请你大保健
这次小黄学乖了,妈蛋这次换阿里大鱼又要被测试骂了,怎么样才能让业务代码尽量不用改呢,百度了一番,找群里的问了一番,小黄决定用一个简单的实现:工厂模式
小黄开始重构代码了,XXSMS类样子操作方法都是一样,我要抽象一个接口出来
public interface ISMS
{
void Init(string key, string pwd);
void Send(string msg, long phone, string client, string tpl);
}
写阿里大鱼及修改之前两个通道的代码
public abstract class BaseSMS : ISMS
{
public virtual void Init(string key, string pwd)
{
throw new NotImplementedException();
} public virtual void Send(string msg, long phone, string client, string tpl)
{
throw new NotImplementedException();
}
protected string FormatTpl(string tpl, string msg, long phoneNumber, string client, string sign)
{
return tpl.Replace("$sign", sign).Replace("$msg", msg).Replace("$client", client);
}
}
public class AlidayuSMS : BaseSMS
{
private string sign;
public override void Init(string key, string pwd)
{
sign = "什么都有的电商公司";
}
public override void Send(string msg, long phone, string client, string tpl)
{
//签名等等把短信发到XSMS公司的接口上
//XXX的复杂发送代码
Console.WriteLine("从阿里大鱼发短信:" + FormatTpl(tpl, msg, phone, client, sign));
}
}
public class XSMS : BaseSMS
{
private string sign;
public override void Init(string key, string pwd)
{
sign = "什么都有的电商公司";
}
public override void Send(string msg, long phone, string client, string tpl)
{
//签名等等把短信发到XSMS公司的接口上
//XXX的复杂发送代码
Console.WriteLine("从XSMS发短信:" + FormatTpl(tpl, msg, phone, client, sign));
}
}
public class FriendSMS : BaseSMS
{
private string sign;
public override void Init(string key, string pwd)
{
sign = "什么都有的电商公司";
}
public override void Send(string msg, long phone, string client, string tpl)
{
//签名等等把短信发到老板朋友公司提供的接口上
//XXX的复杂发送代码
Console.WriteLine("从FriendSMS发短信:" + FormatTpl(tpl, msg, phone, client, sign));
}
}
然后写个简单工厂
public class SMSFactory
{
public static ISMS GetSMS(string type)
{
switch (type.Trim().ToLower())
{
case "xsms": return new XSMS();
case "friendsms": return new FriendSMS();
case "alidayusms": return new AlidayuSMS();
}
throw new Exception("不存在的短信通道:" + type + "");
}
}
修改业务类代码
private static void SendMsg2Client()
{
var cs = GetClient(); if (cs != null && cs.Count > )
{
string tpl = "[$sign]$client您好,$msg";
string key = "";//从配置文件或数据库里取得
string pwd = "";//从配置文件或数据库里取得
string type = "alidayusms";//从配置文件或数据库里取得
var sms = SMSFactory.GetSMS(type);
sms.Init(key, pwd);
foreach (var c in cs)
{
sms.Send("您订购的充气女友已发货,查收后请爱惜使用", c.Key, c.Value, tpl);
}
}
}
上线了,很稳定而且也便宜,老板很满意,给了50块小黄去大保健,小黄把这个大保健的机会让给了测试,因为测试这次怨气大点大,业务代码要测试,几个原来的通道接口也要测试
然后有一天,阿里那边通知:开放平台接口要改为HTTPS,小黄这听到这个消息,冷笑一声,嘿嘿不就改一下这个类而已么
然后小黄把阿里大鱼的类修改一下然后准备上线了,测试听到这个消息:妈蛋你当我透明了啊,跳过我就上线啦
小黄辩称道:就改了一下阿里大鱼那个类而已
测试:不行,你那个工厂依赖大鱼,重新编译了生成的DLL都不知跟原来业务有没有问题
小黄暗暗叫苦,这不是变着法子骗大保健么
让测试再坑了一次大保健,小黄到群里吐苦水,说测试为难自己,众群员也跟着谴责测试,
不过其中一个老司机说:这是你自找的,怪不了测试,你应该让业务代码与这些短信模块解耦,不要依赖这些模块
小黄:老司机,请教怎么破啊
老司机:依赖倒置,让这业务及你这个"工厂"与各个SMS类完全无关,一个SMS类起一个项目生成一个DLL以后你改类就改那个项目,加类就加个新项目,那个模块项目整个好交给测试就行了
小黄:那这个工厂也是要重新编译啊,测试到时也一样会找我麻烦
老司机:把你的工厂升级一下,做成反射工厂或者更一步到位用Ioc容器,需要什么样的短信模块,交给升级的工厂或Ioc容器来完成,这样一来,工厂或IoC容器是完全不用变化,业务代码更是完全不用动,以后测试也轻松了,分分钟反过来请你去大保健
小黄及众群员:嘀,学生卡
在这个依赖倒置的思想指导下,小黄找了一个IoC容器,把SMS模块写到Ioc容器的配置文件里
然后最后一次修改业务代码
private static void SendMsg2Client()
{
var cs = GetClient(); if (cs != null && cs.Count > )
{
string tpl = "[$sign]$client您好,$msg";
string key = "";//从配置文件或数据库里取得
string pwd = "";//从配置文件或数据库里取得 var ctx = new IocContainer("cfg.xml");
var sms = ctx.Resolve<ISMS>();//从Ioc容器取出实现类
sms.Init(key, pwd);
foreach (var c in cs)
{
sms.Send("您订购的充气女友已发货,查收后请爱惜使用", c.Key, c.Value, tpl);
}
}
}
小黄修改了代码,跟测试保证以后不用动业务那些代码,以后测试只测试一下实现模块就OK了,上线运行后,测试邪恶的笑了一下捡起了地上的肥皂 (逃
好了,经过上面纯属虚构的故事,相信大家都对工厂,Ioc和DI等有点理解了
DI (Dependency Injection,依赖注入)
一看这名字不百度都不知是什么意思,那我们再先看一下相关的概念吧
依赖倒置原则(Dependence Inversion Principle,简称DIP)
该死,又多一个概念,引入这个概念的话看来又要引入另一个概念了:解耦
什么是解耦,解耦字面的意思也很明白了解除耦合,解除软件各个模块之间的耦合,让一个模块不要依赖另一个模块
在上面的案例里,解耦就是解除了业务代码对各个SMS模块的耦,业务跟具体实现的模块完全没有依赖,第一版中,业务是编码阶段就跟各SMS类耦合了,严重依赖SMS类,依赖在编码阶段
抽象出接口,然后使用了IoC后这个依赖在编码阶段是没有的,依赖调用实现的SMS的发生在系统运行的阶段,依赖在运行时,IoC把这种依赖完全反转过来了,耦合解除了,依赖倒置了
IoC (Inversion of Control,控制反转)
Ioc的概念也就跟依赖倒置差不多,是控制权的转移,原先由业务代码决定用那个SMS模块的转移到由Ioc容器根据配置文件决定使用什么SMS模块,控制权转移到IoC框架上.
Ioc思想实现的Ioc容器就是负责按配置文件注入依赖(DI)的模块到容器里返回给业务调用
简单说,IoC容器是就一个豪华版工厂,自动化装配的工厂,工厂知道是什么吧,就是我把产品规格发给你,你把产品给我,我不管你给的是怎么制作怎么实现的产品,用什么材料我一概不管,我只要合我规格的就行。
IoC就是这样的一个工厂,我们在业务代码里调用IoC容器(工厂),把需求(产品规格)发给IoC容器,容器返回实现类(产品)给业务,业务就可以按这个规格来草作这个产品了
IoC容器就是负责注入依赖的模块
粗浅见解,打脸轻点
造轮子目标
环境当然是.net core下了
支持配置文件
支持注册单例
支持延迟加载
我不是标题党,用.net魔法真的可以是直接new的速度,当然这个多了一层调用,肯定会下降一丁点,但速度比反射型的不知高那里去了
待续,不会太监,我不是给大鱼打广告
一步一步造个IoC轮子(一):IoC是什么的更多相关文章
- 一步一步造个IoC轮子(二),详解泛型工厂
一步一步造个Ioc轮子目录 一步一步造个IoC轮子(一):Ioc是什么 一步一步造个IoC轮子(二):详解泛型工厂 一步一步造个IoC轮子(三):构造基本的IoC容器 详解泛型工厂 既然我说IoC容器 ...
- 一步一步造个IoC轮子(三):构造基本的IoC容器
一步一步造个Ioc轮子目录 一步一步造个IoC轮子(一):Ioc是什么 一步一步造个IoC轮子(二):详解泛型工厂 一步一步造个IoC轮子(三):构造基本的IoC容器 定义容器 首先,我们来画个大饼, ...
- 如何一步一步用DDD设计一个电商网站(四)—— 把商品卖给用户
阅读目录 前言 怎么卖 领域服务的使用 回到现实 结语 一.前言 上篇中我们讲述了“把商品卖给用户”中的商品和用户的初步设计.现在把剩余的“卖”这个动作给做了.这里提醒一下,正常情况下,我们的每一步业 ...
- (转) 一步一步学习ASP.NET 5 (四)- ASP.NET MVC 6四大特性
转发:微软MVP 卢建晖 的文章,希望对大家有帮助.原文:http://blog.csdn.net/kinfey/article/details/44459625 编者语 : 昨晚写好的文章居然csd ...
- 一步一步深入spring(2)-三种方式来实例化bean
在一步一步深入spring(1)--搭建和测试spring的开发环境中提到了一种实例化bean的方式,也是最基本的使用构造器实例化bean 1.使用构造器实例化bean:这是最简单的方式,Spring ...
- 一步一步构建手机WebApp开发——页面布局篇
继上一篇:一步一步构建手机WebApp开发——环境搭建篇过后,我相信很多朋友都想看看实战案例,这一次的教程是页面布局篇,先上图: 如上图所示,此篇教程便是教初学者如何快速布局这样的页面.废话少说,直接 ...
- 通过Dapr实现一个简单的基于.net的微服务电商系统(四)——一步一步教你如何撸Dapr之订阅发布
之前的章节我们介绍了如何通过dapr发起一个服务调用,相信看过前几章的小伙伴已经对dapr有一个基本的了解了,今天我们来聊一聊dapr的另外一个功能--订阅发布 目录:一.通过Dapr实现一个简单的基 ...
- 通过Dapr实现一个简单的基于.net的微服务电商系统(三)——一步一步教你如何撸Dapr
目录:一.通过Dapr实现一个简单的基于.net的微服务电商系统 二.通过Dapr实现一个简单的基于.net的微服务电商系统(二)--通讯框架讲解 三.通过Dapr实现一个简单的基于.net的微服务电 ...
- 一步一步学ROP之gadgets和2free篇(蒸米spark)
目录 一步一步学ROP之gadgets和2free篇(蒸米spark) 0x00序 0x01 通用 gadgets part2 0x02 利用mmap执行任意shellcode 0x03 堆漏洞利用之 ...
随机推荐
- [JS Compose] 6. Semigroup examples
Let's we want to combine two account accidently have the same name. , friends: ['Franklin'] } , frie ...
- Android JNI编程(六)——C语言函数指针、Unition联合体、枚举、Typedef别名、结构体、结构体指针
版权声明:本文出自阿钟的博客,转载请注明出处:http://blog.csdn.net/a_zhon/. 目录(?)[+] 一:函数指针 1.函数指针顾名思义就是定义一个指针变量指向一个函数,和一级指 ...
- Linux下使用Python的Tkinter库出现的No module named _tkinter问题
这是由于python的版本没有包含tkinter的模块,只需要把tk的package安装就可以了. 一般在linux才出现,windows版本一般已经包含了tkinter模块.
- JS和CSS压缩部署,提高访问效率
一直想把项目中的js和css压缩下,今天终于搞定了. 先说说几个注意的问题,目标影响着你对应的解决办法:1.压缩后的文件,是否要直接覆盖旧的文件2. 单个压缩文件重命名,还是整个目录换个名字,同时文件 ...
- 微信测试号开发之九 微信网页授权:页面获取用户openid
原文链接:https://blog.csdn.net/qq_37936542/article/details/78981369 一:配置接口 注意:这里填写的是域名(是一个字符串),而不是URL,因此 ...
- C语言学习笔记:12_变量的存储方式和生存期
/* * 12_变量的存储方式和生存期.c * * Created on: 2015年7月5日 * Author: zhong */ #include <stdio.h> #include ...
- Innodb单表数据物理恢复
本文将介绍使用物理备份恢复Innodb单表数据的方法 前言: 随着innodb的普及,innobackup也成为了主流备份方式.物理备份对于新建slave,全库恢复的需求都能从容应对. 但当面临单表数 ...
- 29个月过去了,CSDN排名前200了:排名不断靠前的过程中,自己的技术水平和竞争力一定会不断向上
刚刚在csdn博客又发表了一篇,工作问题总结,突然发现,我的博客排名终于进入前200了. 这又是一个伟大的里程碑啊. 在过去29个月的时间里,排名从"千里之外" 到"19 ...
- 简洁常用权限系统的设计与实现(一):构造权限菜单树的N(N>=4)种方法
权限系统,Web开发常见标准子系统之一.结合自己的一些思考和实践,从本篇开始权限系统的设计与实现之路. 最近,重构了项目的权限菜单构造过程,向前端返回json格式的权限树. 这一篇,只是大致介绍下这个 ...
- AnimatorSet和PropertyValuesHolders.ofKeyframe
如果要多个动画配合工作,需要把他们放入AnimatorSet中 ObjectAnimator animator1 = ObjectAnimator.ofFloat(...); animator1.se ...