spring

2.控制反转IoC
IoC全名Inversion of Control,如果中文硬要翻译过来的话,就是「控制反转」。初看IoC,从字面上不容易了解其意义,我觉得要了解IoC,最好先从Dependency Inversion开始了解,也就是依赖关系的反转。
Dependency Inversion在面向对象的设计原则之依赖倒置原则(DIP,Dependence Inversion Principle)中有着清楚的解釋。
简单的说,在模块设计时,高层的抽象模块通常是与业务相关的模块,它应该具有重用性,而不依赖于低层的实现模块,例如如果低层模块原先是软盘存取模式,而高层模块是个存盘备份的需求,如果高层模块直接叫用低层模块的函式,则就对其产生了依赖关系。请看下面的例子:






void Copy(){
   int c;
   while ((c = ReadKeyboard()) != EOF)       
     WritePrinter(c);
}
这是僵化和不易改动的例子,为什么呢?很显然,如果我还要将内容输出到磁盘上(如下图所示),那么我们必须改动Copy的内容,并进行重新的测试和编译。


改动后的程序如下所示:
enum OutputDevice {printer, disk};
void Copy(OutputDevice dev){
   int c;
   while((c = ReadKeyboard())!= EOF)          
      if(dev == printer)
         WritePrinter(c);
      else
         WriteDisk(c);
}
如果要继续添加别的输入或输出方式,该程序还是无法重用,要对此程序进行修改才能继续使用。
利用依赖倒置原则(DIP),可以解决这个问题。DIP原则,可以从2点来解读:
第1点:高层模块不依赖底层模块,两者都依赖抽象
第2点:抽象不应该依赖于细节,细节应该依赖于抽象
上面所讲的例子如果用DIP原则,结果如下

class Reader {
  public:
    virtual int read()=0;
};

class Writer {
  public:
    virtual void write(int)=0;
};

void Copy(Reader& r, Writer& w){
   int c;
   while((c = r.read()) != EOF)
     w.write(c);
}
这样一来,如果要添加新的输入或输出设备时只要改动相应的类(class Reader,Writer,利用多态来解决上面的问题)就可以了,而其它的程序都不用改动。这就是依赖倒置原则的基本内涵。
在软件设计和构建中我们要遵循“高内聚、低偶合”的原则。那么,依赖对于我们来说究竟是好事还是坏事呢?
首先应该明白的是,类之间如果是零偶合的状态是不能够构建应用程序的,只能构建类库。
但是由于人类的理解力和可控制的范围有限,大多数人难以理解和把握过于复杂的系统。把软件系统划分成多个模块,可以有效控制模块的复杂度,使每个模块都易于理解和维护。但在这种情况下,模块之间就必须以某种方式交换信息,也就是必然要发生某种耦合关系。如果某个模块和其它模块没有任何关联(哪怕只是潜在的或隐含的依赖关系),我们就几乎可以断定,该模块不属于此软件系统,应该从系统中剔除。如果所有模块之间都没有任何耦合关系,其结果必然是:整个软件不过是多个互不相干的系统的简单堆积,对每个系统而言,所有功能还是要在一个模块中实现,这等于没有做任何模块的分解。
因此,模块之间必定会有这样或那样的依赖关系,永远不要幻想消除所有依赖。但是,过强的耦合关系(如一个模块的变化会造成一个或多个其他模块也同时发生变化的依赖关系)会对软件系统的质量造成很大的危害。特别是当需求发生变化时,代码的维护成本将非常高。所以,我们必须想尽办法来控制和消解不必要的耦合,特别是那种会导致其它模块发生不可控变化的依赖关系。依赖倒置、控制反转就是人们在和依赖关系进行艰苦卓绝的斗争过程中不断产生和发展起来的。
我们下面来继续一步一步的说明这个问题。
看下面的程序:
#include <floppy.h>
....
void save() {
        ....
        saveToFloppy()
    }
}
由于save()程序依赖于saveToFloppy(),如果今天要更换低层的存储模块为Usb碟,则这个程序没有办法重用,必须加以修改才行,低层模块的更动造成了高层模块也必须跟着更动,这不是一个好的设计方式,我们希望模块都依赖于模块的抽象,这样才可以重用高层的业务设计。
如果以面向对象的方式来设计,依赖倒置(Dependency Inversion)的解释变为程序不应依赖实现,而是依赖于抽象,实现必须依赖于抽象。我们来看看下面这个Java程序:
BusinessObject.java
public class BusinessObject {
    private FloppyWriter writer = new FloppyWriter();
    ....
  
    public void save() {
        ...
        writer.saveToFloppy();

    }
}

public class FloppyWriter {
   
    ....  //相应的写盘的代码
  

你可能感兴趣的:(spring,C++,c,C#,IOC)