• 依赖注入和控制反转


    依赖注入和控制反转到底是什么意思?

    控制反转(Ioc):调用者不再创建被调用者的实例,由IOC容器框架创建(C#中常用的IOC框架有Autofac/Unity等等),这种方式称为控制反转

    依赖注入(DI):容器框架将创建好的实例注入到调用者称为依赖注入

    依赖倒置原则(DIP)

    高层模块不应依赖于低层模块,两者应该依赖于抽象。

    抽象不不应该依赖于实现,实现应该依赖于抽象。

    使用Ioc的好处是什么?

    控制反转是面向对象编程中的一种设计原则,可以用来降低代码之间的耦合度,Ioc把创建和查找依赖对象的控制权交给容器,由容器进行注入,所以对象与对象之间是松散耦合,传统的应用程序都是由我们在类内部主动创建依赖对象,从而导致类与类之间是紧耦合

    举例

    class SqlDal
    {
        public void Add()
        {
            Console.WriteLine("向SQLServer数据库添加一条新订单");
        }
    }
    class Order
    {
        SqlDal sqlDal = new SqlDal();
    
        public void Add()
        {
            sqlDal.Add();
        }
    }

    首先定义了SqlDal类用于SqlServer数据库的读写操作,再定义Order类负责订单的逻辑处理,因为订单数据是要插入到数据库的,所以在Order类中定了SqlDal类的变量并初始化.这里Order是依赖于SqlDal类的

    控制台调用

    static void Main(string[] args)
    {
        Order order = new Order();
        order.Add();
        Console.ReadKey();
    }

    这是传统开发中比较常见的方式,如果这时候数据库改为了mysql,那么SqlDal是无法继续使用了,需要重新定义mysqlDal,负责mysql数据库的读写操作

    class MySqlDal
    {
        public void Add()
        {
            Console.WriteLine("向MySql数据库添加一条新订单");
        }
    }

    由于Order类中直接引用了SqlDal类的对象,所以也需要同步修改为MySqlDal

    class Order
    {        
        MySqlDal mySqlDal = new MySqlDal();
    
        public void Add()
        {
            mySqlDal.Add();
        }
    }

    OK,可以满足当前需求了,但是如果后期类似的情况再次出现,就意味着需要将刚才的操作重新做一次,显然这不是一个良好的设计,类与类之间是高度耦合的,可扩展性较差,它违背了DIP原则,高层模块Order不应依赖于底层模块SqlDal、MySqlDal,两者应该依赖于抽象

    改写代码

    public interface IDal
    {
        void Add();
    }
    class SqlDal : IDal
    {
        public void Add()
        {
            Console.WriteLine("向SQLServer数据库添加一条新订单");
        }
    }
    class Order
    {
        private IDal _dal;
    
        /// <summary>
        /// 构造函数注入
        /// </summary>
        /// <param name="dal"></param>
        public Order(IDal dal)
        {
            _dal = dal;
        }
        public void Add()
        {
            _dal.Add();
        }
    }

    第一步:定义接口IDal,添加方法Add()

    第二步:定义SqlDal继承IDal接口并实现接口中的Add()方法

    第三步:在Order类中添加私有变量用于存储抽象并在构造函数中传递具体依赖对象

    控制台调用

    static void Main(string[] args)
    {
        Order order = new Order(new SqlDal());
        order.Add();
        Console.ReadKey();
    }
    class MySqlDal : IDal
    {
        public void Add()
        {
            Console.WriteLine("向MySql数据库添加一条新订单");
        }
    }
    Order order = new Order(new MySqlDal());
    order.Add();

    输出结果是一样的,但是这里将依赖对象SqlDal对象的创建和绑定转移到了Order外部来实现,这就解除了Order与SqlDal类的耦合关系,如果现在出现需要更改数据库为MySql的需求,只需要定义MySqlDal类继承IDal并实现Add()方法,然后外部绑定依赖,不需要修改Order类内部的代码即可实现替换,很明显这种方式程序的可扩展性更高

    属性注入

    上面所示的方式是在Order类的构造函数中注入依赖对象,还可以使用属性注入的方式,顾名思义,属性注入是通过属性来传递依赖,因此在Order类中定义一个属性

    class Order
    {
        private IDal _dal;
    
        /// <summary>
        /// 属性注入
        /// </summary>
        public IDal Dal
        {
            get { return _dal; }
            set { _dal = value; }
        }

    public void Add() { _dal.Add(); } }

    在控制台调用时给属性赋值从而传递依赖

    static void Main(string[] args)
    {          
        Order order = new Order();
        order.Dal = new SqlDal();
        order.Add();            
        Console.ReadKey();
    }

    接口注入

    相比构造函数注入和属性注入,接口注入显得有些复杂,使用也不常见。具体思路是先定义一个接口,包含一个设置依赖的方法。然后依赖类,继承并实现这个接口

    public interface IDependent
    {
        void SetDepend(IDal idal);
    }
    class Order: IDependent
    {
        private IDal _dal;
    
        public void Add()
        {
            _dal.Add();
        }
    
        public void SetDepend(IDal idal)
        {
            _dal = idal;
        }
    }

     通过SetDepend方法传递依赖

     static void Main(string[] args)
     {
         Order order = new Order();
         order.SetDepend(new SqlDal());
         order.Add();
         Console.ReadKey();
     }

     Ioc容器

    前面所有的例子中,我们都是通过手动的方式来创建依赖对象,并将引用传递给被依赖模块,对于大型项目来说,相互依赖的组件比较多。如果还用手动的方式自己来创建和注入依赖的话,显然效率很低,而且往往还会出现不可控的场面。正因如此,Ioc容器诞生了。Ioc容器实际上是一个DI框架,它能简化我们的工作量。它包含以下几个功能 

    • 动态创建、注入依赖对象
    • 管理对象生命周期
    • 映射依赖关系

    总结:DIP是软件设计的一种思想,Ioc则是基于DIP衍生出的一种软件设计模式。DI是Ioc的具体实现方式之一,使用最为广泛。Ioc容器是DI构造函注入的框架,它管理着依赖项的生命周期以及映射关系

  • 相关阅读:
    string与stringbuilder的区别
    Web负载均衡的几种实现方式
    JS 禁用鼠标右键
    JS中的!=、== 、!==、===的用法和区别。
    SQL Server Change Tracking
    关于更新发布CSS和JS文件的缓存问题
    Authorization in Cloud Applications using AD Groups
    英语学习[ZZ]
    我奋斗了18年,不是为了和你一起喝咖啡
    我奋斗了18年才和你坐在一起喝咖啡
  • 原文地址:https://www.cnblogs.com/GnailGnepGnaw/p/10743235.html
Copyright © 2020-2023  润新知