热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

C#--依赖注入

本文主要分享【】,技术文章【C#--依赖注入】为【Tracy-Mc】投稿,如果你遇到设计模式相关问题,本文相关知识或能到你。小编在之前面试某家企业时,面试官提出了一个问题,虽然按经验,说出了解决方

本文主要分享【】,技术文章【C#--依赖注入】为【Tracy-Mc】投稿,如果你遇到设计模式相关问题,本文相关知识或能到你。

小编在之前面试某家企业时,面试官提出了一个问题,虽然按经验,说出了解决方法,面试官也表示此方法可以实现,且提出了另一种方案,就是“依赖注入”。

面试官的题目是这样子的:如果现在公司有个程序,假设是关于动物园的程序,有些许动物(动物库A)已经加到了动物园里了,里面的动物都完成了动物该有的行为,然后程序已经测试通过,没有问题并已经发布。现在问题是,动物园里要添加新的动物种类,请问,如何不修改动物库A的代码的情况下,将新的动物物种添加到动物园里(题目大概就是这个意思,无非就是说,原来程序不允许修改,只能新增加别的类库,并完成原来的那个类库中的行为,差不多就是这个意思的啦!)。

小编给的方案是,使用反射,好了,这个不是今天的话题,不做详细方案介绍。而面试官提出的方案就是----依赖注入。

面试回来后,总结面试中遇到的问题,其中就对依赖注入进行了一下研究,还是收获很多,以下就是研究这个依赖注入的DEMO。

先看解决方案架构,是个控制台程序

主程序是Zoo,BLL是执行动物的行为,动物库A就是LocalAnimal,其实就是我们熟知的三层架构。有过一定经验的人都应该知道,普通的三层架构中,UI(Zoo)依赖于->BLL依赖于->DAL(LocalAnimal),而这样的设计会导致每一层之间存在很强的耦合关系。点到为止,不详细说了,不是此篇的重点。

我们先看LocalAnimal

先是IAnimal这个接口

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace LocalAnimal
{
    ///  /// 动物接口类 /// 
    public interface IAnimal
    {
        void Voice();  //叫声
    }
}

 接口很简单,里面就是动物应该所拥有的行为,此处定义了叫声

OK,现在看看Animal文件夹下的动物们

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace LocalAnimal.Animal
{
    ///  /// 白鳍豚 /// 
    public class White_Flag_Dolphin:IAnimal
    {
        public void Voice()
        {
            Console.WriteLine("吱吱吱");
        }
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace LocalAnimal.Animal
{
    ///  /// 熊猫 /// 
    public class Panda:IAnimal
    {
        public void Voice()
        {
            Console.WriteLine("嚯嚯嚯");
        }
    }
}

每种动物都实现了动物接口的叫声方法,其中熊猫的叫声是“嚯嚯嚯”(小编也没见过熊猫,不知道怎么叫的,随便写的),白鳍豚的叫声是“吱吱吱”(大概是这样吧)

OK,现在为止,这些动物都是存在的了,但是要放到动物园里,并且让他们开心的叫起来啊!

先看看业务(BLL,动物叫)里的代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using LocalAnimal;
using LocalAnimal.Animal;

namespace BLL
{
    public class AnimalVoice
    {
        IAnimal _iAnimal = null;
        public AnimalVoice(IAnimal iAnimal)
        {
            this._iAnimal = iAnimal;  //构造注入
        }
        public void Voice()
        {
            _iAnimal.Voice();
        }
    }
}

此处就是重点了,实现依赖注入的方法之一是构造注入,也就是使用构造函数进行依赖项注入。

看UI(Zoo)中的代码

using System.Text;
using LocalAnimal;
using LocalAnimal.Animal;
using BLL;

namespace Zoo
{
    class Program
    {
        static void Main(string[] args)
        {
            //动物园里引进了熊猫
            //IAnimal iAnimal = new Panda();
            //AnimalVoice animalVoice = new AnimalVoice(iAnimal);
            //animalVoice.Voice();

            //动物园里引进了白鳍豚
            IAnimal iAnimal = new White_Flag_Dolphin();
            AnimalVoice animalVoice = new AnimalVoice(iAnimal);
            animalVoice.Voice();

            Console.ReadKey();
        }
    }
}

执行结果

到这里,我们可以看到,无论我们将来需要动物园中增加多少动物,只需要在动物库(LocalAnimal)中增加该动物,并且在Zoo中实例化该动物,就能开始完成动物的业务(叫),而业务层(BLL)中的代码完全不需要改变。

OK,开始完成本篇开始面试官给我出的面试题。

如题描述,如果LocalAnimal中的代码已经完成编码并关闭,已经不允许在里面做任何的改动,则此时,如果动物园要引入新的动物怎么办呢?没问题,接下来,可以看到面向接口开发以及使用依赖注入解耦的优点。

我们新建一个类库,取名为ForeignAnimal(相当于引入了新的.dll,这也是面试官想看到,我们新增加了一个扩展文件,而不需要修改它的LocalAnimal),如下图

 ForeignAnimal中引入了LocalAnimal,其目的是为了实现LocalAnimal中的IAnimal接口,以完成对BLL中的依赖注入,看袋鼠(Kangaroo类)的代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using LocalAnimal;

namespace ForeignAnimal.NewAnimal
{
    ///  /// 袋鼠 /// 
    public class Kangaroo : IAnimal
    {
        public void Voice()
        {
            Console.WriteLine("咚咚咚");
        }
    }
}

 与Panda和White_Flag_Dolphin中的代码完全一致,没有任何不同。那现在Zoo中要开始引入袋鼠了,此时,先在Zoo中引入ForeignAnimal,如下图

引入 ForeignAnimal的动态库后,Zoo开始引进袋鼠,如下代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using LocalAnimal;
using LocalAnimal.Animal;
using BLL;
using ForeignAnimal.NewAnimal;

namespace Zoo
{
    class Program
    {
        static void Main(string[] args)
        {
            //动物园里引进了熊猫
            //IAnimal iAnimal = new Panda();
            //AnimalVoice animalVoice = new AnimalVoice(iAnimal);
            //animalVoice.Voice();

            //动物园里引进了白鳍豚
            //IAnimal iAnimal = new White_Flag_Dolphin();
            //AnimalVoice animalVoice = new AnimalVoice(iAnimal);
            //animalVoice.Voice();

            //动物园里引进了袋鼠
            IAnimal iAnimal = new Kangaroo();
            AnimalVoice animalVoice = new AnimalVoice(iAnimal);
            animalVoice.Voice();

            Console.ReadKey();
        }
    }
}

执行结果

执行结果,也没问题,并且也可以看到,我们完全没有动过业务层(BLL)的代码。

到这里,就完成面试官提出的问题,我在完全没有修改LocalAnimal的情况下,新增了ForeignAnimal,并且将ForeignAnimal中的动物成功引进到了Zoo中,这就叫--依赖注入。

现在,如果我们看一下代码,我们只依赖于业务访问层中数据访问层的抽象,而业务访问层是使用的是数据访问层实现的接口。因此,我们遵循了更高层次对象和更低层次对象都依赖于抽象的原则,抽象是更高层次对象和更低层次对象之间的契约。

现在,有同学又要说了,“不行啊!我能不能也不修改Zoo中的代码呢?”,答案是可以的,此时需要用到反射,代码如下

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using LocalAnimal;
using LocalAnimal.Animal;
using BLL;
using ForeignAnimal.NewAnimal;
using System.Reflection;

namespace Zoo
{
    class Program
    {
        static void Main(string[] args)
        {
            //动物园里引进了熊猫
            //IAnimal iAnimal = new Panda();
            //AnimalVoice animalVoice = new AnimalVoice(iAnimal);
            //animalVoice.Voice();

            //动物园里引进了白鳍豚
            //IAnimal iAnimal = new White_Flag_Dolphin();
            //AnimalVoice animalVoice = new AnimalVoice(iAnimal);
            //animalVoice.Voice();

            //动物园里引进了袋鼠
            //IAnimal iAnimal = new Kangaroo();
            //AnimalVoice animalVoice = new AnimalVoice(iAnimal);
            //animalVoice.Voice();

            Assembly assembly = Assembly.LoadFrom("ForeignAnimal.dll");  //如果是需要LocalAnimal,则此处字符串改成 LocalAnimal.dll 即可
            IAnimal iAnimal = (IAnimal)assembly.CreateInstance("ForeignAnimal.NewAnimal.Kangaroo", true);
            AnimalVoice animalVoice = new AnimalVoice(iAnimal);
            animalVoice.Voice();

            Console.ReadKey();
        }
    }
}

执行结果

结果也没问题。 

如下图,红框中的字符串均可写入到配置文件中,这样的话,无论新增了多少动态库、类,只需要在配置文件中做新增修改就可以,Zoo中的代码无需再修改。

总结

依赖注入的优点:

1、传统的代码,每个对象负责管理与自己需要依赖的对象,导致如果需要切换依赖对象的实现类时,需要修改多处地方。同时,过度耦合也使得对象难以进行单元测试。

2、依赖注入把对象的创造交给外部去管理,很好的解决了代码紧耦合(tight couple)的问题,是一种让代码实现松耦合(loose couple)的机制。

3、松耦合让代码更具灵活性,能更好地应对需求变动,以及方便单元测试。

依赖注入的缺点:

使用依赖注入时,往往会配合反射使用,这在一定程度上影响程序的性能。

本文《C#--依赖注入》版权归Tracy-Mc所有,引用C#--依赖注入需遵循CC 4.0 BY-SA版权协议。


推荐阅读
  • 本文介绍了Python爬虫技术基础篇面向对象高级编程(中)中的多重继承概念。通过继承,子类可以扩展父类的功能。文章以动物类层次的设计为例,讨论了按照不同分类方式设计类层次的复杂性和多重继承的优势。最后给出了哺乳动物和鸟类的设计示例,以及能跑、能飞、宠物类和非宠物类的增加对类数量的影响。 ... [详细]
  • 云原生边缘计算之KubeEdge简介及功能特点
    本文介绍了云原生边缘计算中的KubeEdge系统,该系统是一个开源系统,用于将容器化应用程序编排功能扩展到Edge的主机。它基于Kubernetes构建,并为网络应用程序提供基础架构支持。同时,KubeEdge具有离线模式、基于Kubernetes的节点、群集、应用程序和设备管理、资源优化等特点。此外,KubeEdge还支持跨平台工作,在私有、公共和混合云中都可以运行。同时,KubeEdge还提供数据管理和数据分析管道引擎的支持。最后,本文还介绍了KubeEdge系统生成证书的方法。 ... [详细]
  • 阿,里,云,物,联网,net,core,客户端,czgl,aliiotclient, ... [详细]
  • C# 7.0 新特性:基于Tuple的“多”返回值方法
    本文介绍了C# 7.0中基于Tuple的“多”返回值方法的使用。通过对C# 6.0及更早版本的做法进行回顾,提出了问题:如何使一个方法可返回多个返回值。然后详细介绍了C# 7.0中使用Tuple的写法,并给出了示例代码。最后,总结了该新特性的优点。 ... [详细]
  • 本文介绍了三种方法来实现在Win7系统中显示桌面的快捷方式,包括使用任务栏快速启动栏、运行命令和自己创建快捷方式的方法。具体操作步骤详细说明,并提供了保存图标的路径,方便以后使用。 ... [详细]
  • 本文介绍了PE文件结构中的导出表的解析方法,包括获取区段头表、遍历查找所在的区段等步骤。通过该方法可以准确地解析PE文件中的导出表信息。 ... [详细]
  • Java学习笔记之面向对象编程(OOP)
    本文介绍了Java学习笔记中的面向对象编程(OOP)内容,包括OOP的三大特性(封装、继承、多态)和五大原则(单一职责原则、开放封闭原则、里式替换原则、依赖倒置原则)。通过学习OOP,可以提高代码复用性、拓展性和安全性。 ... [详细]
  • 模板引擎StringTemplate的使用方法和特点
    本文介绍了模板引擎StringTemplate的使用方法和特点,包括强制Model和View的分离、Lazy-Evaluation、Recursive enable等。同时,还介绍了StringTemplate语法中的属性和普通字符的使用方法,并提供了向模板填充属性的示例代码。 ... [详细]
  • 解决.net项目中未注册“microsoft.ACE.oledb.12.0”提供程序的方法
    在开发.net项目中,通过microsoft.ACE.oledb读取excel文件信息时,报错“未在本地计算机上注册“microsoft.ACE.oledb.12.0”提供程序”。本文提供了解决这个问题的方法,包括错误描述和代码示例。通过注册提供程序和修改连接字符串,可以成功读取excel文件信息。 ... [详细]
  • 本文介绍了C++中省略号类型和参数个数不确定函数参数的使用方法,并提供了一个范例。通过宏定义的方式,可以方便地处理不定参数的情况。文章中给出了具体的代码实现,并对代码进行了解释和说明。这对于需要处理不定参数的情况的程序员来说,是一个很有用的参考资料。 ... [详细]
  • 本文介绍了OC学习笔记中的@property和@synthesize,包括属性的定义和合成的使用方法。通过示例代码详细讲解了@property和@synthesize的作用和用法。 ... [详细]
  • 本文主要解析了Open judge C16H问题中涉及到的Magical Balls的快速幂和逆元算法,并给出了问题的解析和解决方法。详细介绍了问题的背景和规则,并给出了相应的算法解析和实现步骤。通过本文的解析,读者可以更好地理解和解决Open judge C16H问题中的Magical Balls部分。 ... [详细]
  • 本文讨论了使用差分约束系统求解House Man跳跃问题的思路与方法。给定一组不同高度,要求从最低点跳跃到最高点,每次跳跃的距离不超过D,并且不能改变给定的顺序。通过建立差分约束系统,将问题转化为图的建立和查询距离的问题。文章详细介绍了建立约束条件的方法,并使用SPFA算法判环并输出结果。同时还讨论了建边方向和跳跃顺序的关系。 ... [详细]
  • 本文介绍了如何在给定的有序字符序列中插入新字符,并保持序列的有序性。通过示例代码演示了插入过程,以及插入后的字符序列。 ... [详细]
  • c语言\n不换行,c语言printf不换行
    本文目录一览:1、C语言不换行输入2、c语言的 ... [详细]
author-avatar
莹TX_937
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有