IoC控制反转设计原则——实现松耦合

IOC是一种设计原则(虽然,有很多人将它当成是一种设计模式),不是设计模式。它提供了高层级的设计指南,但不提供实现细节。意味着你可以自由实现IoC原则。

1.IoC设计原则

正如IOC(控制的反转)的名字一样,IoC被用来反转不同类型的控制在面向对象设计中获得松耦合。这里的控制指的是类拥有的除了主要职责的其他的职责。这包括对应用程序流的控制,对象创建或依赖的对象创建绑定的流的控制。

在这里插入图片描述

打个比方说,你开车去上班,意味着你控制着车。IOC原则则建议你反转控制,意味着不是你自己开车,你可以租一辆出租车,让另外一个人来开,这就是所谓的控制反转,这样一来,你就不用再管控制车的任何操作,让司机去控制,你就可以专心做自己的事了。

IoC原则帮助设计松耦合的类,使得这些类可测试、可维护和可扩展。让我们来理解一下Ioc是怎样返回不同种类的控制的。

1.1.控制程序流

如Java的典型应用,从main()函数开始执行的。main()函数控制了程序的流程,或者换句话说,是用户交互的顺序。

class Program { static void Main(string[] args) { bool continueExecution = true; do { Console.Write("Enter First Name:"); var firstName = Console.ReadLine(); Console.Write("Enter Last Name:"); var lastName = Console.ReadLine(); Console.Write("Do you want to save it? Y/N: "); var wantToSave = Console.ReadLine(); if (wantToSave.ToUpper() == "Y") SaveToDB(firstName, lastName); Console.Write("Do you want to exit? Y/N: "); var wantToExit = Console.ReadLine(); if (wantToExit.ToUpper() == "Y") continueExecution = false; }while (continueExecution); } private static void SaveToDB(String firstName, String lastName) { //save firstName and lastName to the database here.. } }

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

1.2.控制依赖对象的创建

IoC也可以应用到创建依赖类的对象。什么是依赖呢?

public class A
{ B b; public A() { b = new B(); } public void Task1() { // do something here.. b.SomeMethod(); // do something here.. }

}

public class B { public void SomeMethod() { //doing something.. }
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

在上面这个例子中,A调用b.SomeMethod()来完成它的task1。如果没有B类的对象,A类不能够完成它的任务。因此,我们可以说“A类依赖于B类”或者“B类是A类的依赖”。

在面向对象设计的方法中,类需要互相交互才能完成一个或多个应用程序的功能。例如上面的例子,A类创建并管理B类的对象的生命周期。本质上,A类控制依赖类的对象的创建和生存时间。IoC原则建议反转控制,这意味着将控制委托给另一个类。 换句话说,就是把A的依赖关系创建的控制反转给另一个类来做,如下所示:

public class A
{ B b; public A() { b = Factory.GetObjectOfB(); } public void Task1() { // do something here.. b.SomeMethod(); // do something here.. }
}

public class Factory
{ public static B GetObjectOfB() { return new B(); }
}


  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

如你所见,A使用了工厂类来获得B类的对象。因此,我们把依赖对象的创建从A类反转到了一个工厂类里。A类不再负责创建B类的对象。取而代之的是A类将使用工厂类来获取B类的对象。

在面向对象设计中,类应该被设计成松耦合的。松耦合意味着一个类里的变化不应该强制其他类也跟着变化。所以这样一来,整个应用变得可维护和可扩展。

2.从典型的n层体系架构来理解IoC

我们再从典型的n层体系架构来理解IoC。
在这里插入图片描述
在典型的n层体系架构里,UI(User Interface)使用Service层来获取和保存数据;而Service层使用BusinessLogic类来对数据应用业务规则;BusinessLogic类依赖DataAccess类,DataAccess类是用来检索数据或将数据保存底层数据库的。

public class CustomerBusinessLogic
{ DataAccess _dataAccess; public CustomerBusinessLogic() { _dataAccess = new DataAccess(); }IoC is a principle, not a pattern. It just gives high-level design guidelines but does not give implementation details. You are free to implement the IoC principle the way you want. public string GetCustomerName(int id) { return _dataAccess.GetCustomerName(id); }
}

public class DataAccess
{ public DataAccess() { } public string GetCustomerName(int id) { return "Dummy Customer Name"; // get it from DB in real app }
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

正如你所见,CustomerBusinessLogic类依赖于DataAccess类,它创建DataAccess类的对象并用来获得customer的数据。CustomerBusinessLogic不仅要负责创建DataAccess类的对象,还要管理其生命周期。CustomerBusinessLogic类和DataAccess类紧耦合在一起。这样的设计会有以下这些问题:

  • 当DataAccess类有变化就会导致CustomerBusinessLogic也要跟着改,例如,我们添加、删除或重命名DataAccess类里的任何方法,我们都要相应地修改CustomerBusinessLogic类。
  • 假设customer的数据来自不同的数据库或web services,并且在将来我们可能需要创建不同的类等,都会导致CustomerBusinessLogic类要做相应的修改。
  • CustomerBusinessLogic类使用new关键创建DataAccess类对象,可能有多个类使用DataAccess类和创建它的对象。所以当修改DataAccess的类名,你就需要找出所有使用DataAccess类的地方,并做相应修改。这些都是用于创建相同类的对象并维护其依赖关系的重复性代码。
  • 因为CustomerBusinessLogic类创建一个具体的DataAccess类对象,使用它不能够独立测试,因为DataAccess类不能够用模拟类来代替。

为了解决以上这些问题,获得松耦合设计,我们可以使用IoC和DIP原则共同来解决。IoC是一种设计原则,不是一种设计模式,它指提供高层设计指南,不提供实现细节。你可以自由地使用自己的方式去实现这一原则。以下设计模式(但不限于)都实现了IoC原则:
在这里插入图片描述
我们用工厂模式(Factory)来实现IoC,首先创建一个工厂类,它负责返回DataAccess类:

public class DataAccessFactory
{ public static DataAccess GetDataAccessObj() { return new DataAccess(); }
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

接着,使用DataAccessFactory类在CustomerBusinessLogic类里获得DataAccess类的对象:

public class CustomerBusinessLogic
{ public CustomerBusinessLogic() { } public string GetCustomerName(int id) { DataAccess _dataAccess =  DataAccessFactory.GetDataAccessObj(); return _dataAccess.GetCustomerName(id); }
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

正如你所见,CustomerBusinessLogic类使用DataAccessFactory.GetCustomerDataAccessObj()方法获得DataAccess类的对象,而不是用new关键字创建它。因此,我们反转了CustomerBusinessLogic类依赖的DataAccess类的对象的创建的控制,通过DataAccessFactory工厂类。
与IoC一起,我们也可以用DIP原则, Strategy设计模式和依整注入DI(Dependency Injection)来一起用出以获得松耦合。

文章来源: blog.csdn.net,作者:WongKyunban,版权归原作者所有,如需转载,请联系作者。

原文链接:blog.csdn.net/weixin_40763897/article/details/109027096

(完)