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)

讲故事型

C#基础知识之依赖注入 (bbsmax.com)

posted @ 2023-02-01 11:36  驼七  阅读(21)  评论(0)    收藏  举报