对DIP、IoC、DI、IoC容器的解释,静下心,认真看完就能理解

来源:互联网 发布:如何评价pdd人品 知乎 编辑:程序博客网 时间:2024/06/08 12:21
1、基本概念总结:
<1>、hibernate:
     hibernate比较常用的环境是ORM机制,就是将传统的关系型数据库,转化为面向对象编程思想来操作操作数据库。
 举个例子来解释:例如一个表单上有名字、年龄、爱好、性别。。。。等许多的关键字,在没有使用ORM机制之前,你需要
 为这些字段的内容分别创建一个变量来进行保存,然后再一条条的写sql语句,这样会很麻烦,做很多重复的工作,而在你
 使用了hibernate中的ORM机制以后,就会将数据库中的表映射为一个对象,然后在表单对应的input的name上,填写对应对
 象的对应属性,然后在保存的时候,在提交到的action中,定义一个student的对象实例,那么这些数据就会自动保存在这个
 对象之中了。接下来你就只需要保存一下这个对象就可以了,而不再需要一条一条的进行保存了。
<2>、SessionFactory:(顾名思义,就是产生session的工厂)
    SessionFactory接口负责初始化hibernate。它充当数据存储源的代理,并负责创建session对象。
<3>、Session:
     这里要注意一下,hibernate中的session并不是http中的session。HttpSession对象称为用户会话。
 而hibernate中的session是用来表示,应用程序和数据库的一次会话。通常将每个session实例和一个数据库事务绑定,也
 就是每执行一个数据库事务,都应该先创建一个新的Session实例,在使用Session之后,要记得关闭session。    
<4>、DIP依赖倒置原则:
     依赖倒置原则:一种软件架构设计的原则。
     具体形象的例子:比如说生活中应用到的atm取款机和银行卡,众所周知,任何一张银行卡都可以从个大银行的atm取款机取
 款,银行卡的设计规则是依据各个atm取款机统一的设计规则来设计的,而不是atm根据银行卡来设计在这个例子中,ATM相当于高
 层模块,而银行卡相当于底层模块。也就是说ATM不依赖于具体的哪种银行卡,它只需要定义好银行卡的规则参数(接口),所有实现
 了这种规格参数的银行卡都可以在ATM上使用.所以,在软件设计方面,依赖倒置原则,它转换了依赖,高层模块不再依赖于底层模块
 的实现,而底层模块依赖于高层模块定义的接口。通俗的讲,就是高层模块定义接口,底层模块负责实现。
     使用接口实现而不是继承的原因:在类的继承中,只能做单重继承,而实现接口时,一次可以实现多个接口。
     如果底层模块设定接口,那么当有新的底层模块类出现的时候,高层模块就会需要修改代码,来实现新的底层模块的接口。这样,
 就破坏了开发封闭的原则。
·总结:DIP的优点:
      (1)、系统更柔韧:可以修改一部分代码而不影响其他的模块。
      (2)、系统更健壮:可以修改一部分代码而不会让系统崩溃。
      (3)、系统更高效:组件松耦合,且可以复用,提高开发效率。
<5>、控制反转Ioc:
     控制反转(IoC):一种反转流、依赖和接口的方式(DIP的具体实现方式)。
     DIP是一种软件架构的设计原则:高层模块不应该依赖于底层模块.它只告诉了你一种设计原则,但是并没有告诉你如何去做.
  Ioc控制反转就是一种设计模式,它就来告诉你如何去做,来解除相互依赖模块的耦合。
·控制反转(IoC):它为相互依赖的组件提供抽象,将依赖(底层模块)对象的获取交给第三方(系统)来控制,也就是说不在高层模块
  中进行获取底层模块对象的操作,即依赖对象不在被依赖模块的类中直接通过new来获取。
   例如:ATM自身并没有插入具体的银行卡,而是将插卡的操作交给人来完成。在软件设计中就是把依赖对象的实例化操作交给第三
  方来完成。
·设计原则:原则为我们提供指南,它告诉我们什么是对的,什么是错的。它不会告诉我们如何解决问题。它仅仅给出一些准则,
  以便我们可以设计好的软件,避免不良的设计。一些常见的原则,比如DRY、OCP、DIP等。        
·设计模式:模式是在软件开发过程中总结得出的一些可重用的解决方案,它能解决一些实际的问题。一些常见的模式,比如工
  厂模式、单例模式等等
·总结:高层模块的类不应该依赖于底层模块,而两者应该依赖于抽象(抽象类不能够实例化)。为了实现这种设计原则,我们可以使用
  Ioc来优化代码。Ioc有两种常见的实现方式:依赖注入和服务定位。
·注解:解释抽象类:
       对于普通方法,有"{}"表示方法体,有了方法体就可以进行实例化,而当没有方法体的时候,就表示的是抽象方法,抽象方法
  不能够进行实例化。有抽象方法的类就表示抽象类。抽象类不能够进行实例化,可以继承进行覆写。
·对于类和接口的一些关系,遵循以下原则(不管是抽象类还是实体类都遵从以下原则):
       1、接口只能继承接口,还可以继承多个接口,用逗号隔开。接口不能继承类。
       2、类只能实现接口,还可以实现多个接口。类能够继承类,只能继承一个类。    、
<6>、依赖注入(DI).
  是一种反转方式,是一种Ioc设计模式的具体方式。    
  控制反转(Ioc)是一种重要的方式,就是说把依赖对象的创建和绑定转移到被依赖对象类的外部来实现(第三方,外部即系统来完成)。 
·依赖注入(ID):它提供一种机制,将需要依赖(底层模块)对象的引用传递给被依赖(高层模块)对象。
  所谓的引用就是new出的一个对象的对象名,实质是地址。
·依赖注入DI有三种方式:构造函数注入,属性注入,接口注入。
  (1)、构造函数注入:
     |-:原先代码(订单入库的设计):
        1)、我们会先定义一个SqlServletDal类,用于数据库的读写:
          public class SqlServletDal{
                 public void Add(){
                       Console.WriteLine("在数据库中添加一条订单!");
                 } 
          }     
        2)、然后我们定义一个Order类,用于完成订单入库的逻辑处理。
          public class Order{
              private readonly SqlServerDal dal = new SqlServerDal();//添加一个私有变量保存数据库操作的对象     
              public void Add(){
                       dal.Add();
              }
          }
          !!!注意:这个类就相当于是高层模块,我们的设计原则就是在上线以后最好不要改变这个类。
        3)、然后我们写一个控制台程序来检验成果:
          using System;
          using System.Collections.Generic;
          using System.Linq;  
          using System.Text; 
          namespace DIPTest{
          class Program{
               static void Main(string[] args){
                      Order order = new Order();
                      order.Add();
                      Console.Read();
               }
          }
        }        
    ·对于这种代码的不好之处就是,当boss要求换成另外一种数据库的时候,需要改高层模块:
       4)、如果要用Access数据库,需要再重新定义一个类,然后还得改Order类:
          public class AccessDal{
                 public void Add(){
                  Console.WriteLine("在ACCESS数据库中添加一条记录!");
                 }
          }


          public class Order{
                 private readonly AccessDal dal = new AccessDal();//添加一个私有变量保存数据库操作的对象
                 public void Add(){
                  dal.Add();
                 }
          }
   |-:使用DI构造方法注入:
       1)、因为设计原则是高层模块和底层模块之间的耦合靠的是抽象,所以我们先需要定义SqlServerDal的抽象类型
         IDataAccess,并在IDataAccess接口中声明一个Add方法。
          public interface IDataAccess{
                  void Add();
          } 
       2)、然后在SqlServerDal类中,实现IDataAccess接口。
         public class SqlServerDal:IDataAccess{
          public void Add(){
           Console.WriteLine("在数据库中添加一条订单!");
          }
         }
       3)、修改Order类:
         public class Order{
            private IDataAccess _ida;//定义一个私有变量保存抽象
            //构造函数注入
            public Order(IDataAccess ida){
            _ida = ida;//传递依赖
            } 
            public void Add(){
            _ida.Add();
            }
         }
      !!!注意:这样写完之后,以后再修改数据库的话,就不在需要改这个类了。也就是说依赖的注入不在被依赖的类中完成,
    而是在外部完成。
       4)、控制台程序。
        using System;
        using System.Collections.Generic;
        using System.Linq;
        using System.Text;
 
        namespace DIPTest{
         class Program{
          static void Main(string[] args){
            SqlServerDal dal = new SqlServerDal();//在外部创建依赖对象
            Order order = new Order(dal);//通过构造函数注入依赖,通过引用来注入。 
            order.Add();
            Console.Read();
        }
    }
}
      5)、如果使用Access数据库的话:
        public class AccessDal:IDataAccess
{
        public void Add()
        {
            Console.WriteLine("在ACCESS数据库中添加一条记录!");
        }
}
然后在控制台程序中重新绑定依赖关系:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace DIPTest
{
    class Program
    {
        static void Main(string[] args)
        {
             AccessDal dal = new AccessDal();//在外部创建依赖对象
               Order order = new Order(dal);//通过构造函数注入依赖 
               order.Add(); 
            Console.Read();
        }
    }
}
    注解:显然,我们不需要修改Order类的代码,就完成了Access数据库的移植,这无疑体现了IoC的精妙。
   (2)、属性注入:
       1)、 顾名思义,属性注入是通过属性来传递依赖。因此,我们首先需要在依赖类Order中定义一个属性:
public class Order
{
      private IDataAccess _ida;//定义一个私有变量保存抽象
        //属性,接受依赖
        public IDataAccess Ida
       {
           set { _ida = value; }
           get { return _ida; }
       } 
       public void Add()
       {
           _ida.Add();
       }
}
       2)、然后在控制台程序中,给属性赋值,从而传递依赖:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace DIPTest
{
    class Program
    {
        static void Main(string[] args)
        {
            AccessDal dal = new AccessDal();//在外部创建依赖对象
            Order order = new Order();
            order.Ida = dal;//给属性赋值 
            order.Add();
            Console.Read();
        }
    }
}
我们可以得到上述同样的结果。
   (3)、注入接口实现:
      1)、相比构造函数注入和属性注入,接口注入显得有些复杂,使用也不常见。具体思路是先定义一个接口,
      包含一个设置依赖的方法。然后依赖类,继承并实现这个接口。
      首先定义一个接口: 
public interface IDependent
{
           void SetDependence(IDataAccess ida);//设置依赖项
}
      2)、依赖类实现这个接口:
public class Order : IDependent
  {
      private IDataAccess _ida;//定义一个私有变量保存抽象
 
     //实现接口
     public void SetDependence(IDataAccess ida){
        _ida = ida;
      } 
     public void Add(){
      _ida.Add();
            }
         }
      3)、控制台程序通过SetDependence方法传递依赖:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace DIPTest{
    class Program{
        static void Main(string[] args){
            AccessDal dal = new AccessDal();//在外部创建依赖对象
          Order order = new Order();
            order.SetDependence(dal);//传递依赖
            order.Add();
            Console.Read();
        }
    }
}
我们同样能得到上述的输出结果。
<7>、Ioc容器。
     Ioc容器是一种框架,是依赖注入的框架,用来映射依赖,管理对象创建和生存周期(DI框架)。
   在前面,我们是通过手动的方式来创建依赖对象,并将引用传递给依赖模块.例如:
     SqlServerDal dal = new SqlServerDal();//在外部创建依赖对象
     Order order = new Order(dal);//通过构造函数注入依赖 
·对于大型项目来说,相互依赖的组件比较多。如果还用手动的方式,自己来创建和注入依赖的话,
显然效率很低,而且往往还会出现不可控的场面。正因如此,IoC容器诞生了。IoC容器实际上是一
个DI框架,它能简化我们的工作量。它包含以下几个功能:
     (1)、动态创建、注入依赖对象。
     (2)、管理对象生命周期。
     (3)、映射依赖关系。
<8>、总结:
     DIP是软件的一种设计思想,Ioc就是实现该设计思想的一种设计模式,DI即使实现该模式的具体方法之一,
   Io容器是DI实现的框架,它管理着依赖项的生命周期以及映射关系。
·依赖倒置原则(DIP):一种软件架构设计的原则(抽象概念)。
·控制反转(IoC):一种反转流、依赖和接口的方式(DIP的具体实现方式)。
·依赖注入(DI):IoC的一种实现方式,用来反转依赖(IoC的具体实现方式)。
·IoC容器:依赖注入的框架,用来映射依赖,管理对象创建和生存周期(DI框架)。 
原创粉丝点击