【调侃】IOC前世今生

发布时间:2026/7/4 8:26:08

【调侃】IOC前世今生 前些天参与了公司内部小组的一次技术交流主要是针对《IOC与AOP》本着学而时习之的态度及积极分享的精神我就结合一个小故事来初浅地剖析一下我眼中的“IOC前世今生”以方便初学者能更直观的来学习与理解IOC也作抛砖引玉之用。虽说故事中的需求有点小但看客可在脑海中尽量把他放大想象成一个很大的应用系统一、IOC雏形1、程序V1.0话说多年以前UT公司提出一个需求要提供一个系统其中有个功能可以在新春佳节之际给公司员工发送一封邮件。邮件中给大家以新春祝福并告知发放一定数额的过节费。经分析决定由张三、李四和王五来负责此系统的开发。其中由张三负责业逻辑控制模块 LogicController的开发,此处简化为UT.LogicController.exe 由李四负责祝福消息管理类GreetMessageService并集成到组件 UT.MessageService.dll中由王五负责邮件功能帮助类EmailHelper并提供组件 UT.Email.dll。类依赖关系如下王五邮件功能模块核心代码如下public class EmailHelper { public void Send(string message) { Console.Write(Frome email: message); } }李四消息管理模块核心代码如下public class GreetMessageService { EmailHelper greetTool; public GreetMessageService() { greetTool new EmailHelper(); } public void Greet(string message) { greetTool.Send(message); } }张三业务集成模块核心代码如下string message 新年快乐过节费5000.; MessageService.GreetMessageService service new MessageService.GreetMessageService(); service.Greet(message);三人经过一个月的艰苦奋战终于大功告成系统也在春节其间成功发出问候信。企业如此关怀给员工带来无比的温暖因此深受全体员工好评春节过后相应的功能也移植到了与“UT公司”相关的“UT编辑部”和“UT房产”类似的应用当中并在后继的“元宵”、“端午”、“中秋”等节日中得以广泛应用。2、程序V2.0又是一个年关将至……说真的过节费的多少有时可能直接影响整个假日的行程安排、从而影响假日的整体质量因此部门领导高度重视。而邮件通知的方式在边远山区常常因为受网络环境的影响而无法正常收取许多在外过年的同事对此颇有微词。后经多方考证决得采用当下非常主流的电话语言播报的方式进行通知。于是乎张三、李四、王五又忙起来了。但李四却有点头疼了因为他的模块现在不仅在“UT公司”内部使用而且还在“UT编辑部”和“UT房产”也都有独立运行。如何让此处变化影响最小就得费点脑筋。为了达到较好的效果李四决定按以下方式进行整改。①、初始设计方案如下首先为了能让不同“祝福方式”能有效替换决定以“面向接口”的方式来进行分离。同时让EmailHelper的邮件通知类和TelephoneHelper的语音播报类都实现此接口。核心代码如下public interface ISendable { void Send(string message); }public class EmailHelper : ISendable { public void Send(string message) { Console.Write(Frome email: message); } }public class TelephoneHelper : ISendable { public void Send(string message) { Console.Write(Frome telephone: message); } }再者为了方便兼容新旧产品要求Controller决定当前采用什么方式进行通信并以参数方式传给消息管理模块核心代码如下public enum SendToolType { Email, Telephone, }【备注】:上述代码并不是一个优秀的设计在后继的优化方案当中将被去除。public class GreetMessageService { ISendable greetTool; public GreetMessageService(SendToolType sendToolType) { if (sendToolType SendToolType.Email) { greetTool new UT.EmailV20.EmailHelper(); } else if (sendToolType SendToolType.Telephone) { greetTool new UT.TelephoneV20.TelephoneHelper(); } } public void Greet(string message) { greetTool.Send(message); } }【备注】:上述代码并不是一个优秀的设计在后继的优化方案当中将被优化。最后业务集成模块结合具体业务需求进行适当的调整核心代码如下string message 新年快乐过节费5000.; GreetMessageService service new GreetMessageService(SendTool.Telephone); service.Greet(message);眼看即将完工但李四却越看越不顺眼因为考虑到以后可能再添加新的祝福方式这种未来的不确定性一定会让李四现有的枚举SendToolType和 GreetMessageService中的构造函数不断的进行更改这将会是一个没完没了工作。再说了既然张三要传SendToolType给我也就是说在具体产品应用时张三的模块肯定是知道要采用什么方式进行祝福那么何不让他直接把祝福方式的实例而不是简单的方式类型给我呢这样我不就省事了吗于是乎把设计进行了优化。②、优化后设计方案又是一个月的苦战……王五的代码不受影响。李四删除 SendToolType枚举同进把GreetMessageService改成如下public class GreetMessageService { ISendable greetTool; public GreetMessageService(ISendable sendtool) { greetTool sendtool; } public void Greet(string message) { greetTool.Send(message); } }张三也把业务逻辑控制部分改成如下string message 新年快乐 过节费5000.; ISendable greetTool new TelephoneHelper(); GreetMessageService service new GreetMessageService(greetTool); service.Greet(message);最终张三更新UT.LogicController.exe中的实现李四更新了UT.MessageSevice.dll,王五提供新的组件UT.Telephone.dll并把接口集成到一个叫UT.Core.dll的库中。经多方集成测试后系统运行良好【点评】李四此处成功的利用“接口分离”、并结合“依赖倒置”的方式使得自己负责的模块初步具备了应对新增祝福方式的扩展要求。同时由于其采用的“依赖注入”方式要求李四的业务逻辑控制模块对其所需的“ISendable”实例进行注入理论上已经初步具体了“IOC反转控制”的雏形。对“IOC反转控制”此时带来的优势就是确保了“红色框”内的模块是具有应对变化的能力在后继新增新祝福方式时UT.MessageService.dll组件可以完全不做任何修改。3、V2.1由于电话语言播报必须接听、过后不便留底查询等不足也常被人们诟病因此短信通知的方式被提上议程。在此要求下王五提供了新的组件UT.GSN.dll。核心代码如下public class SMSHelper : ISendable { public void Send(string message) { Console.WriteLine(Frome SMS: message); } }张三也把代码改成了如下string message 新年快乐 过节费5000.; ISendable greetTool new SMSHelper(); GreetMessageService service new GreetMessageService(greetTool); service.Greet(message);李四坐享其成4、V2.2祝福方式日新月异人们的要求也是不断发展没过多久短信方式太呆板、信息量不足等缺陷也暴露出来微信深受大伙青睐。在此要求下王五提供了新的组件UT.Wechat.dll。核心代码如下public class WechatHelper : ISendable { public void Send(string message) { Console.WriteLine(Frome wechat: message); } }张三也把代码改成了如下string message 新年快乐 过节费5000.; ISendable greetTool new WechatHelper(); GreetMessageService service new GreetMessageService(greetTool); service.Greet(message);李四再次坐享其成二、IOC扩展1、李四的逍遥自在与张三的焦头烂额由于采用了IOC反转控制的思想现在不管系统如何变化李四负责的模块总的来说还是相当稳定因此这些年李四过的可谓逍遥自在。然而相比之下张三却因为产品在UT公司、UT编辑部、UT房产等都有独立应用且各自使用的版本又不尽相同因此要同时维护三个版本可谓是焦头烂额。当然张三曾经也想统一各个版本从而实现代码的统一维护。为此还专门与各相关主管沟通过、协调过然而由为UT编辑部与电信服务商早有合作所有短信免费因此短信方式最得人心而UT房产基于对信息接收者身份的特殊性考虑邮件通知被认为是不二选择。因此张三统一版本的梦想最终还是无果而终。我们来看看此时的张三同时维护着三个系统其中各自核心代码基本如下UT公司微信方式string message 新年快乐 过节费5000.; ISendable greetTool new WechatHelper(); GreetMessageService service new GreetMessageService(greetTool); service.Greet(message);UT编辑部短信方式string message 新年快乐 过节费5000.; ISendable greetTool new SMSHelper(); GreetMessageService service new GreetMessageService(greetTool); service.Greet(message);UT房产(邮件方式)string message 新年快乐 过节费5000.; ISendable greetTool new EmailHelper(); GreetMessageService service new GreetMessageService(greetTool); service.Greet(message);这些年本着对工作和客户的认真负责张三长时间在这些“版本维护”、“产品兼容”等脏活累活中摸爬滚打现在是心力憔悴……2、张三的出路某日张三与李四觥筹交错、把酒言欢……酒过三巡张三对李四说当年你的模块因“IOC反转控制”而脱身却把“变化点”反转到我模块由我来生成特定的对象然后再向你注入。这样你是轻松了但我却深陷泥潭……面对张三的吐槽李四只能给张三进行细心分析首先、MessageService消息管理模块作为一个消息专用服务其实对“是采用邮件还是微信方式进行祝福”这样的功能性把控本身是不具主动权由这个模块来负责实在是有点鞭长莫及即便强扭到一起这瓜也铁定甜不了。还有本着单一职责的原则本消息服务其实是不方便过多地去处理本应该是业务逻辑处理的类似“选择祝福方式”这种事情。理论上作为业务集成方的“LogicController”负责处理这类业务应该是责无傍代。再者作为新增需求王五为此而新增组件dll那是必不可少张三作为业务的总集成方也是难以脱身由于新增需求而引起的变化对张三和王五产生影响也是情理之中。即便退一万步来说就算没有“反转控制”张三也是要面对变化的就像V2.0初始方案中的传入SendToolType参数因此有无“反转控制”对张三而言该变的始终还是要变化。那么现在采用“IOC反转控制”而成全了李四的稳定对张三来说这是个“利人不损已”的买卖。最后不管从架构设计还是开发效率上来说“IOC反转控制”虽说把变化点从李四的“MessageService”模块反转到了张三的“LogicController”模块当中但这符合“SOLID面向对象设计”的原则可以说是一个好的设计本无可厚非听完李四的论述张三觉得甚是有理酒不免醒了三分由于两人都是这个行业打拼多年的老鸟争论也是点到即止。马上把交流的重点转移到“如何解决张三同时维护三个产品”的尴尬处境上来。经过深入分析两人觉得要脱困必须解决好如下两个问题①如何有效创建“ISendable”实例减少由于新增祝福方式对实例创建的影响②如何减少新增祝福方式而对“LogicController”模块的冲击以减少维护成本

相关新闻