IOC、DI_mst
1. 参考链接 (12条消息) C#--依赖注入_Tracy-Mc的博客-CSDN博客_c# 依赖注入
2. 实践心得
2.1 理解:
依赖注入:
原始:在调用方法的时候需要自己主动去 new 这个对象,然后使用
依赖注入:有专门的容器去 new 这个对象 ,调用这个方法的函数只需等待 容器 new 完,然后使用即可
控制反转:
原始:调用时 按需要直接去 new 对象 控制权在自己手中
现在:容器去做这个操作,控制权在容器手中
2.2 参考链接的理解
问题:
如果现在公司有个程序,假设是关于动物园的程序,有些许动物(动物库A)已经加到了动物园里了,里面的动物都完成了动物该有的行为,然后程序已经测试通过,没有问题并已经发布。现在问题是,动物园里要添加新的动物种类,请问,如何不修改动物库A的代码的情况下,将新的动物物种添加到动物园里(题目大概就是这个意思,无非就是说,原来程序不允许修改,只能新增加别的类库,并完成原来的那个类库中的行为,差不多就是这个意思的啦!)。
项目结构:(向下依赖)
Zoo:主程序、UI
BLL:执行动物的行为
LocalAnimal:动物库
问题解决:
修改动物库,加入新动物
直接在 LocalAniamal 中加入新动物 ,然后在 Zoo 中实例化该动物即可
不修改动物库,加入新的动物
新建一个动物库(与 LocalAniamal 结构相同):然后在 Zoo 中添加 新动物库 的引用 然后实例化该动物即可
只修改动物库 不修改 Zoo
利用反射
Assembly assembly = Assembly.LoadFrom("ForeignAnimal.dll"); //如果是需要LocalAnimal,则此处字符串改成 LocalAnimal.dll 即可 IAnimal iAnimalas = (IAnimal)assembly.CreateInstance("ForeignAnimal.NewAnimal.Kangaroo", true); AnimalVoice animalVoiceas = new AnimalVoice(iAnimalas); animalVoiceas.Voice();
3. 总结:
依赖注入的优点:
1、传统的代码,每个对象负责管理与自己需要依赖的对象,导致如果需要切换依赖对象的实现类时,需要修改多处地方。同时,过度耦合也使得对象难以进行单元测试。
2、依赖注入把对象的创造交给外部去管理,很好的解决了代码紧耦合(tight couple)的问题,是一种让代码实现松耦合(loose couple)的机制。
3、松耦合让代码更具灵活性,能更好地应对需求变动,以及方便单元测试。
依赖注入的缺点:
使用依赖注入时,往往会配合反射使用,这在一定程度上影响程序的性能。
4.附上抄的代码
4.1项目结构

4.2 代码
4.2.1 BLL —— AnimalVoice.cs
using LocalAnimal; using System; using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks; namespace BLL { public class AnimalVoice { IAnimal _iAnimal = null; public AnimalVoice(IAnimal iAnimal) { this._iAnimal = iAnimal;//构造方法注入 } public void Voice() { _iAnimal.Voice(); } } }
4.2.2 ForeignAnimal —— Kangaroo.cs
using LocalAnimal; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ForeignAnimal.NewAnimal { /*如题描述,如果LocalAnimal中的代码已经完成编码并关闭,已经不允许在里面做任何的改动, *则此时,如果动物园要引入新的动物怎么办呢?没问题,接下来,可以看到面向接口开发以及使用依赖注入解耦的优点。 *我们新建一个类库,取名为ForeignAnimal(相当于引入了新的.dll,这也是面试官想看到,我们新增加了一个扩展文件, *而不需要修改它的LocalAnimal) * *ForeignAnimal中引入了LocalAnimal,其目的是为了实现LocalAnimal中的IAnimal接口, *以完成对BLL中的依赖注入,看袋鼠(Kangaroo类)的代码 */ /// <summary> /// 袋鼠叫 /// /// </summary> public class Kangaroo : IAnimal { public void Voice() { Console.WriteLine("袋鼠叫了!"); } } }
4.2.3 LocalAnimal —— *
4.2.3.1 Panda.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace LocalAnimal.Animal { /// <summary> /// 熊猫叫 /// </summary> public class Panda : IAnimal { public void Voice() { Console.WriteLine("熊猫说话了!"); } } }
4.2.3.2 While-Flag-Dolphin.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace LocalAnimal.Animal { /// <summary> /// 白海豚叫 /// 吱吱 /// </summary> public class White_Flag_Dolphin : IAnimal { public void Voice() { Console.WriteLine("海豚叫"); } } }
4.2.3.3 IAnimal.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace LocalAnimal { /// <summary> /// 动物接口类 /// 接口很简单,里面就是动物应该所拥有的行为,此处定义了叫声 /// </summary> public interface IAnimal { void Voice(); } }
4.2.4 Zoo —— Program.cs
// See https://aka.ms/new-console-template for more information using LocalAnimal; using LocalAnimal.Animal; using BLL; using ForeignAnimal.NewAnimal; using System.Diagnostics; using System.Reflection; //动物园引入了熊猫 IAnimal iAnimalPanda = new Panda(); AnimalVoice animalVoicePanda = new AnimalVoice(iAnimalPanda); animalVoicePanda.Voice(); //动物园引入白海豚 IAnimal iAnimal = new White_Flag_Dolphin(); AnimalVoice animalVoice = new AnimalVoice(iAnimal); animalVoice.Voice(); //Console.ReadKey(); /** * 到这里,我们可以看到,无论我们将来需要动物园中增加多少动物, * 只需要在动物库(LocalAnimal)中增加该动物,并且在Zoo中实例化该动物, * 就能开始完成动物的业务(叫),而业务层(BLL)中的代码完全不需要改变。 * */ ///依赖注入:新建ForeignAnimal类库,实现新添加新的动物叫,而不改变原来LoalAnimal类库的代码 ///动物园里又来了袋鼠 IAnimal iAnimalKangaroo = new Kangaroo(); AnimalVoice animalVoiceKangaro = new AnimalVoice(iAnimalKangaroo); animalVoiceKangaro.Voice(); //Console.ReadKey(); /*到这里,就完成面试官提出的问题,我在完全没有修改LocalAnimal的情况下, * 新增了ForeignAnimal,并且将ForeignAnimal中的动物成功引进到了Zoo中, * 这就叫--依赖注入。现在,如果我们看一下代码,我们只依赖于业务访问层中数据访问层的抽象, * 而业务访问层是使用的是数据访问层实现的接口。因此,我们遵循了更高层次对象和更低层次对象都依赖于抽象的原则, * 抽象是更高层次对象和更低层次对象之间的契约。现在,有同学又要说了,“不行啊!我能不能也不修改Zoo中的代码呢?”, * 答案是可以的,此时需要用到反射,代码 **/ Assembly assembly = Assembly.LoadFrom("ForeignAnimal.dll"); //如果是需要LocalAnimal,则此处字符串改成 LocalAnimal.dll 即可 IAnimal iAnimalas = (IAnimal)assembly.CreateInstance("ForeignAnimal.NewAnimal.Kangaroo", true); AnimalVoice animalVoiceas = new AnimalVoice(iAnimalas); animalVoiceas.Voice(); Console.ReadKey(); /*总结 * 依赖注入的优点: * 1、传统的代码,每个对象负责管理与自己需要依赖的对象,导致如果需要切换依赖对象的实现类时,需要修改多处地方。同时,过度耦合也使得对象难以进行单元测试。 * 2、依赖注入把对象的创造交给外部去管理,很好的解决了代码紧耦合(tight couple)的问题,是一种让代码实现松耦合(loose couple)的机制。 * 3、松耦合让代码更具灵活性,能更好地应对需求变动,以及方便单元测试。 * * 依赖注入的缺点: * 使用依赖注入时,往往会配合反射使用,这在一定程度上影响程序的性能。 */
其他注入方法:
实现依赖注入的三种方式 - 95后的码农 - 博客园 (cnblogs.com)
讲故事型

浙公网安备 33010602011771号