关键词:
一、引言
IOC-Invertion of Control,即控制反转,是一种程序设计思想,世上本没有路,走的人多了便有了路,本文将一步步带你了解IOC设计思想的演进之路。
在学习IOC之前我们先初步了解几个概念
依赖(Dependency):就是有联系,表示一个类依赖于另一个类
依赖倒置原则(DIP):设计模式六大原则之一,是一种软件架构设计原则
控制反转(IOC):一种软件设计原则,上层对下层的依赖(即底层模块的获得)交给第三方
依赖注入(DI):实现IOC的一种方式、手段
IOC容器:依赖注入的框架,用来映射依赖,管理对象创建和生存周期
二、依赖
依赖就是有联系,有地方使用它就是有依赖它,下面看一个简单的示例
class BMW { public string Show() { return "宝马"; } } class ChinesePeople { private BMW bmw = new BMW(); public void Run() { Console.WriteLine($"今天开{bmw.Show()}上班"); } } class Program { static void Main(string[] args) { ChinesePeople people = new ChinesePeople(); BMW bmw = new BMW(); people.Run(); Console.Read(); } }
上面中国人开着宝马去上班,客户端有使用中国人、宝马汽车两个对象,中国人中有使用对象宝马汽车,我们可以从中找到三个依赖关系:
客户端依赖对象ChinesePeople;
客户端依赖对象BMW;
ChinesePeople依赖对象BMW;
三、依赖倒置原则
过些日子来了新需求,中国人不仅要开宝马去上班,还要开奔驰去上班,如果按照上面直接依赖关系的方式去做,我们就需要修改ChinesePeople类,让它实现一个参数为宝马的重载方法Run(),显然这样不是好的设计,我们总不能每次新增一种汽车(即修改下层模块)都要去修改ChinesePeople类吧(相对于汽车为上层模块),太麻烦了。。。
先简单分析一下,耦合关系就是依赖关系,如果依赖关系很重,牵一发而动全身,将很难维护扩展,耦合关系越少,系统会越稳定,因此要较少依赖
定义:A.高层模块不应依赖于底层模块,两者应该依赖于抽象
B.抽象不应该依赖于细节,细节应该依赖于抽象
在这个图中,我们发现高层模块定义接口,将不直接依赖于下层模块,下层模块负责实现高层模块定义的接口,下面看代码demo:
interface ICar { string Show(); } class BMW:ICar { public string Show() { return "宝马"; } } class BenZ : ICar { public string Show() { return "奔驰"; } } interface IPeople { void Run(ICar bmw); } class ChinesePeople :IPeople { public void Run(ICar bmw) { Console.WriteLine($"今天开{bmw.Show()}上班"); } } class Program { static void Main(string[] args) { ICar carBMW = new BMW(); ICar carBenZ = new BenZ(); IPeople people = new ChinesePeople(); people.Run(carBMW); people.Run(carBenZ); Console.Read(); } }
分析:上面代码中,ChinesePeople类不再依赖于具体的汽车,而是依赖于汽车的抽象,这样使得不管换什么样的汽车品牌,中国人都是可以开着去上班的,而且不需要修改ChinesePeople类。想一下,这样是不是挺好的,我们可以得出:上层不再依赖细节,相比面向实现,面向接口较好,因为抽象相比细节要更稳定。
四、控制反转
上面示例中,我们实现了具体的人和具体的汽车的隔离,具体人只和汽车的接口有关。但是Program中main方法里的具体对象写死了,控制权变小,当我要修改美国人开着福特去上班时,就不得不要去修改代码,那怎么把控制权转移呢?
下面看一个简单的示例:
interface ICar { string Show(); } class BMW:ICar { public string Show() { return "宝马"; } } interface IPeople { void Run(ICar bmw); } class ChinesePeople :IPeople { public void Run(ICar bmw) { Console.WriteLine($"今天开{bmw.Show()}上班"); } } class Program { static void Main(string[] args) { string people = ConfigurationManager.AppSettings["people"]; string car = ConfigurationManager.AppSettings["car"]; Assembly assemblypeople = Assembly.Load(people.Split(‘,‘)[1]); Assembly assemblycar = Assembly.Load(car.Split(‘,‘)[1]); Type typepeople = assemblypeople.GetType(people.Split(‘,‘)[0]); Type typecar = assemblypeople.GetType(car.Split(‘,‘)[0]); IPeople ipeople= (IPeople)Activator.CreateInstance(typepeople); ICar icar = (ICar)Activator.CreateInstance(typecar); ipeople.Run(icar); Console.Read(); } }<?xml version="1.0" encoding="utf-8" ?> <configuration> <startup> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" /> </startup> <appSettings> <add key="people" value="MyIOC_IOC.ChinesePeople,MyIOC_IOC"/> <add key="car" value="MyIOC_IOC.BMW,MyIOC_IOC"/> </appSettings> </configuration>
上面代码中,我们使用反射+配置文件的方式,将对象创建的控制权转移到了配置文件,这就是所谓的控制反转
分析,控制反转是将对象创建的控制权交给了第三方,可以是IOC容器,它就相当于工厂,我们要什么对象,工厂给我们什么对象,这样依赖关系就变了,它们(人和车)都依赖于IOC容器,通过IOC容器建立它们之间的依赖关系。(依赖对象不再被依赖模块的类中直接通过new来获取)
五、依赖注入
上面说到的控制反转,我们了解到是将控制权转移,这是我们的目的,配置文件+反射是是一种实现,而依赖注入则提供的是一种思想,或者说是实现IOC的手段。
依赖注入是将对象的创建和绑定转移到被依赖对象的外部来实现。在依赖关系中ChinesePeople类所依赖的对象BMW类的创建和绑定是在ChinesePeople类内部执行的,显然这种方法是不可取的,那我们怎么BMW类的引用传递给ChinesePeople类呢?
方法一 构造函数注入
interface ICar { string Show(); } class BMW:ICar { public string Show() { return "宝马"; } } class ChinesePeopleContructor { private ICar _car; public ChinesePeopleContructor(ICar bmw) { _car = bmw; } public void Run() { Console.WriteLine($"今天开{_car.Show()}上班"); } } static void Main(string[] args) { ICar car = new BMW(); ChinesePeopleContructor people = new ChinesePeopleContructor(car); people.Run(); Console.Read(); }
分析,BMW类对象的创建和绑定转移到ChinesePeople类的外部来实现,解除了两个对象之间的耦合,当需要开奔驰去上班的时候,只需要定义一个奔驰类,外部重新绑定依赖,不需要修改ChinesePeople类的内部,即可是先中国人开奔驰去上班的需求
方法二 属性注入
interface ICar { string Show(); } class BMW:ICar { public string Show() { return "宝马"; } } class ChinesePeopleProperty { private ICar _ICar; public ICar IC { get { return _ICar; } set { _ICar = value; } } public void Run() { Console.WriteLine($"今天开{_ICar.Show()}上班"); } } static void Main(string[] args) { ICar car = new BMW(); ChinesePeopleProperty people = new ChinesePeopleProperty(); people.IC = car; people.Run(); Console.Read(); }
分析,属性注入是通过给属性赋值,从而传递依赖
方法三 接口注入
interface ICar { string Show(); } class BMW:ICar { public string Show() { return "宝马"; } } interface IDependent { void SetDependent(ICar icar); } class ChinesePeopleInterface : IDependent { private ICar _ICar; public void SetDependent(ICar icar) { _ICar = icar; } public void Run() { Console.WriteLine($"今天开{_ICar.Show()}上班"); } } static void Main(string[] args) { ICar car = new BMW(); ChinesePeopleInterface people = new ChinesePeopleInterface(); people.SetDependent(car); people.Run(); Console.Read(); }
分析,接口依赖是定义一个设置依赖的方法,然后被依赖类继承并实现这个接口
六、IOC容器
IOC容器是一个DI框架,主要功能有一下几点
1.动态创建、注入依赖对象;
2.管理对象生命周期
2.映射依赖关系
1.3浅谈spring(ioc容器的实现)
这一节我们来讨论IOC容器到底做了什么。还是借用之前的那段代码ClassPathXmlApplicationContextapp=newClassPathXmlApplicationContext("beans.xml");Carcar=app.getBean(Car.class);System.out.println(car.getBrand()+","+car.getDesc());这里Cla 查看详情
浅谈“面向接口编程”:依赖反转ioc与di(容器控制反转与依赖注入)(代码片段)
IOC:InversionofControlContainersandtheDependencyInjection“Water”by AndyHuan,Malaysia. Location:Malaysia关键词:IOC(容器控制反转),DI(依赖注入),面相接口编程,抽象 查看详情
浅谈springioc(ioc模型)(代码片段)
文章目录前言说明BeanDaulftBeanFactoryBuilderBean对比Spring操作V0.001初步模型效果实现总结前言关于目前我们先解读关于Spring的IOC部分,这个也是个大头。下面是某个大佬的文章,不过这里并不是说查看人家的文章,而是通... 查看详情
spring之ioc
----------------siwuxie095 浅谈IoC IoC(InversionofControl,控制反转)是Spring的核心,贯穿始终 所谓Io 查看详情
浅谈spring5创建对象3种方式以及依赖注入(代码片段)
一背景介绍spring框架里面包含了很多流行的技术,如IOC,DI,SpringlMVC,官方文档地址(https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#spring-core),一开始听这些名词时云里雾里的& 查看详情
spring(02)重新认识ioc
目录Spring(02)重新认识IoC1.IoC发展简介2.IoC主要实现策略3.IoC容器的职责4.IoC容器的实现5.传统IoC容器实现6.轻量级IoC容器7.依赖查找VS.依赖注入8.构造器注入VS.Setter注入9.面试题精选Spring(02)重新认识IoC1.IoC发展简介1983年,RichardE... 查看详情
spring5源码分析(004)——ioc篇之理解ioc
本文主要记录笔者对IoC的一些理解和以及相关参考。目录结构如下:1、对IoC和DI的理解1.1、IoC是什么1.2、为什么需要IoC,IoC可以解决什么问题1.3、IoC和DI1.4依赖注入的3种方式1.4.1、构造器注入1.4.2、setter方法注入1.4.3、接口注... 查看详情
一步一步造个ioc轮子:构造基本的ioc容器
一步一步造个Ioc轮子目录一步一步造个IoC轮子(一):Ioc是什么一步一步造个IoC轮子(二):详解泛型工厂一步一步造个IoC轮子(三):构造基本的IoC容器定义容器首先,我们来画个大饼,定义好构造函数,注册函数及获取函数... 查看详情
typescript浅谈
https://mp.weixin.qq.com/s?__... 查看详情
ioc之2.2ioc容器基本原理(00000001)
2.2.1 IoC容器的概念IoC容器就是具有依赖注入功能的容器,IoC容器负责实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。应用程序无需直接在代码中new相关的对象,应用程序由IoC容器进行组装。在Spring中BeanFactor... 查看详情
spring5ioc容器
细节展示了IOC的底层原理和两种注册对象对象的方法.两种方式我更喜欢使用注解方式,但是使用xml更直观的体现注册对象的过程二.IOC容器(1)IOC底层原理(2)IOC接口(BeanFactory)(3)IOC操作Bean管理(基于xml)(4)IOC操作Bean管理(基于注解)1.... 查看详情
IOC - 具有静态辅助方法的 util 类是不是应该与 IOC 连接?
】IOC-具有静态辅助方法的util类是不是应该与IOC连接?【英文标题】:IOC-ShouldutilclasseswithstatichelpermethodsbewiredupwithIOC?IOC-具有静态辅助方法的util类是否应该与IOC连接?【发布时间】:2011-02-0108:50:16【问题描述】:只是想继续了解I... 查看详情
ioc&aop
1IOC 概念:IoC(InverseofControl,控制反转)是一种设计思想,用于将原本在程序中手动创建对象的控制权,交由Spring框架来管理。IoC在其他语言中也有应用,并非Spirng特有。IoC容器是Spring用来实现IoC的载体,IoC容器实际上就... 查看详情
ioc是什么
1.IoC是什么Ioc全名Ioc—InversionofControl即“控制反转”,不是什么技术而是一种设计思想,意味着想你设计好的对象交给一个容器控制而不是传统的在你的对象内部直接控制。谁控制谁:在net里,我们直接在对象内部通过new创建对... 查看详情
菜鸟认知--dip,ioc,di,ioc容器
...这种设计原则之后谁来具体实现这种原则呢,这时候引进IoC。IoC:控制反转 Ioc是基于DIP提出的反转依赖的思想的设计模式,它提出了可以创建第三方来管理依赖关系。 传统的依赖关系是:对象中创建依赖对象。 IoC的... 查看详情
ioc框架---什么是ioc
1 IoC理论的背景 我们都知道,在采用面向对象方法设计的软件系统中,它的底层实现都是由N个对象组成的,所有的对象通过彼此的合作,最终实现系统的业务逻辑。 &... 查看详情
浅谈javarmi
浅谈JAVA-RMIserverdemo:packagecom.ray.rmi;importjava.rmi.Naming;importjava.rmi.Remote;importjava.rmi.RemoteException;importjava.rmi.registry. 查看详情
ioc容器
...inkphp6与laravel7的容器做一个比较。首先理解下三个概念:IOC(控制反转)、DI(依赖注入)、IOC容器IOC:简单来讲,就是对类的新建、管理交由他人去处理。省去了newClass的步骤。DI:IOC的实现方式,逐层搜索类的依赖,并实例化... 查看详情