• 实现依赖注入的三种方式


    依赖注入(DI)

    控制反转(IoC)一种重要的方式,就是将依赖对象的创建和绑定转移到被依赖对象类的外部来实现。在上述的实例中,Order类所依赖的对象SqlServerDal的创建和绑定是在Order类内部进行的。事实证明,这种方法并不可取。既然,不能在Order类内部直接绑定依赖关系,那么如何将SqlServerDal对象的引用传递给Order类使用呢?

     依赖注入(DI):

    它提供一种机制,将需要依赖(低层模块)对象的引用传递给被依赖(高层模块)对象。通过DI,我们可以在Order类的外部将SqlServerDal对象的引用传递给Order类对象。那么具体是如何实现呢?

    方法一 构造函数注入

    构造函数函数注入,毫无疑问通过构造函数传递依赖。因此,构造函数的参数必然用来接收一个依赖对象。那么参数的类型是什么呢?具体依赖对象的类型?还是一个抽象类型?根据DIP原则,我们知道高层模块不应该依赖于低层模块,两者应该依赖于抽象。那么构造函数的参数应该是一个抽象类型。我们再回到上面那个问题,如何将SqlServerDal对象的引用传递给Order类使用呢

    首选,我们需要定义SqlServerDal的抽象类型IDataAccess,并在IDataAccess接口中声明一个Add方法。

    public interface IDataAccess
    {
            void Add();
    }

     然后在SqlServerDal类中,实现IDataAccess接口。

    复制代码
    public class SqlServerDal:IDataAccess
    {
           public void Add()
           {
               Console.WriteLine("在数据库中添加一条订单!");
           }
    }
    复制代码

     接下来,我们还需要修改Order类。

    复制代码
      public class Order
      {
             private IDataAccess _ida;//定义一个私有变量保存抽象
     
            //构造函数注入
            public Order(IDataAccess ida)
            {
                _ida = ida;//传递依赖
            }
     
            public void Add()
            {
                _ida.Add();
            }
    }
    复制代码

     OK,我们再来编写一个控制台程序。

    复制代码
        class Program
        {
            static void Main(string[] args)
            {
                SqlServerDal dal = new SqlServerDal();//在外部创建依赖对象
                Order order = new Order(dal);//通过构造函数注入依赖
     
                order.Add();
     
                Console.Read();
            }
        }
    复制代码

     输出结果:

    从上面我们可以看出,我们将依赖对象SqlServerDal对象的创建和绑定转移到Order类外部来实现,这样就解除了SqlServerDal和Order类的耦合关系。当我们数据库换成Access数据库时,只需定义一个AccessDal类,然后外部重新绑定依赖,不需要修改Order类内部代码,则可实现Access数据库的操作。

    定义AccessDal类:

    复制代码
    public class AccessDal:IDataAccess
    {
            public void Add()
            {
                Console.WriteLine("在ACCESS数据库中添加一条记录!");
            }
    }
    复制代码

    然后在控制台程序中重新绑定依赖关系:

    复制代码
        class Program
        {
            static void Main(string[] args)
            {
                 AccessDal dal = new AccessDal();//在外部创建依赖对象
                   Order order = new Order(dal);//通过构造函数注入依赖
     
                   order.Add();
     
                Console.Read();
            }
        }
    复制代码

    输出结果:

    显然,我们不需要修改Order类的代码,就完成了Access数据库的移植,这无疑体现了IoC的精妙。

    方法二 属性注入

    顾名思义,属性注入是通过属性来传递依赖。因此,我们首先需要在依赖类Order中定义一个属性:

    复制代码
    public class Order
    {
          private IDataAccess _ida;//定义一个私有变量保存抽象
          
            //属性,接受依赖
            public IDataAccess Ida
           {
               set { _ida = value; }
               get { return _ida; }
           }
     
           public void Add()
           {
               _ida.Add();
           }
    }
    复制代码

     然后在控制台程序中,给属性赋值,从而传递依赖:

    复制代码
        class Program
        {
            static void Main(string[] args)
            {
                AccessDal dal = new AccessDal();//在外部创建依赖对象
                Order order = new Order();
                order.Ida = dal;//给属性赋值
     
                order.Add();
     
                Console.Read();
            }
        }
    复制代码

    我们可以得到上述同样的结果。

     方法三 接口注入

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

    首先定义一个接口: 

    public interface IDependent
    {
               void SetDependence(IDataAccess ida);//设置依赖项
    }

    依赖类实现这个接口:

    复制代码
    public class Order : IDependent
     {
         private IDataAccess _ida;//定义一个私有变量保存抽象
     
         //实现接口
         public void SetDependence(IDataAccess ida)
         {
             _ida = ida;
         }
     
         public void Add()
         {
             _ida.Add();
         }
     
     }
    复制代码

    控制台程序通过SetDependence方法传递依赖:

    复制代码
        class Program
        {
            static void Main(string[] args)
            {
                AccessDal dal = new AccessDal();//在外部创建依赖对象
              Order order = new Order();
     
                order.SetDependence(dal);//传递依赖
     
                order.Add();
     
                Console.Read();
            }
        }
    复制代码

    我们同样能得到上述的输出结果。

     虽说上述三种注入形式避免了修改Order类,但仍然避免不了修改控制台输出的方法。这样来看,减轻了order类的负担,但控制台输出端就必须判断使用的数据库,因此:上述三种注入形式的代码违背了设计模式的开闭原则,仍然有不小的瑕疵,如果解决这个问题呢?

    IoC容器

    前面所有的例子中,我们都是通过手动的方式来创建依赖对象,并将引用传递给被依赖模块。比如:

    SqlServerDal dal = new SqlServerDal();//在外部创建依赖对象
    Order order = new Order(dal);//通过构造函数注入依赖

     对于大型项目来说,相互依赖的组件比较多。如果还用手动的方式,自己来创建和注入依赖的话,显然效率很低,而且往往还会出现不可控的场面。正因如此,IoC容器诞生了。IoC容器实际上是一个DI框架,它能简化我们的工作量。它包含以下几个功能:

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

    目前,比较流行的Ioc容器有以下几种:Ninject、Castle Windsor、Autofac、StructureMap、Unity、Spring.NET、LightInject 等

  • 相关阅读:
    LeetCode --- 字符串系列 --- 解码字母到整数映射
    LeetCode --- 字符串系列 --- 上升下降字符串
    LeetCode --- 字符串系列 --- 机器人能否返回原点
    集合 Set
    LeetCode --- 字符串系列 --- 唯一摩尔斯密码词
    LeetCode --- 字符串系列 --- 转换成小写字母
    LeetCode --- 字符串系列 --- 分割平衡字符串
    LeetCode --- 字符串系列 --- IP 地址无效化
    LeetCode --- 字符串系列 --- 左旋转字符串
    Revit二次开发八 事务标签值
  • 原文地址:https://www.cnblogs.com/cloudcmm/p/13569895.html
Copyright © 2020-2023  润新知