依赖反转个人理解
声明:都是个人理解,不保证都是对的。
什么是依赖:如字面解释,依赖在程序中的体现如下:
public class ClassA { public void DoSomething() { ClassB b = new ClassB(); //调用ClassA.DoSomething()需要先实例化ClassB,则我们可以说ClassA依赖与类ClassB b.DoWork(); } } public class ClassB { public void DoWork() { Console.WriteLine("I am working!"); } }
而如何反转这种依赖关系呢?(DIP)
让我们用代码来说明
lets do it!
首先先实现具体依赖于抽象:
public class ClassA { public void DoSomething() { IWork b = new ClassB(); //还是存在依赖关系 b.DoWork(); } } public class ClassB : IWork //此时ClassB依赖于接口,即具体依赖与抽象 { public void DoWork() { Console.WriteLine("I am working!"); } } public interface IWork { public void DoWork(); }
但是这样还是没有反转依赖关系。
我们采用依赖注入来进行依赖反转:(注:依赖注入是实现依赖反转的一种方法,方法还有很多种)
public class ClassA { private IWork b; public ClassA(IWork b) { this.b = b; //注入接口b } public void DoSomething() { b.DoWork(); //原本“A依赖于B”的关系变成了“把对B的依赖从外部注入到A中”, //A想要调用DoSomething()已经不需要去实例化B,A此时依赖于接口IWork } } public class ClassB : IWork //此时ClassB依赖于接口,即具体依赖与抽象 { public void DoWork() { Console.WriteLine("I am working!"); } } public interface IWork { public void DoWork(); }
在百度了许久之后收获一些说法:
把高层模块和低层模块分别放到不同的包或库。定义行为或服务的接口也放到高层模块所在的包中。这些接口的实现则放到低层接口所在的包。这样要想编译低层模块(包含接口实现)所在的包,就依赖于高层模块所在的包。这样,低层模块依赖于高层模块。
高层的模块不依赖低层模块。高层模块和低层模块都依赖抽象。
抽象不依赖具体。具体依赖抽象。
依赖反转原则的目的是,把高层模块与低层模块解耦。
控制反转即IoC (Inversion of Control),它把传统上由程序代码直接操控的对象的调用权交给容器,通过容器来实现对象组件的装配和管理。所谓的“控制反转”概念就是对组件对象控制权的转移,从程序代码本身转移到了外部容器。
依赖注入之所以更流行是因为它是一种更可取的方式:让容器全权负责依赖查询,受管组件只需要暴露JavaBean的setter方法或者带参数的构造子或者接口,使容器可以在初始化时组装对象的依赖关系。
好莱坞原则:IoC体现了好莱坞原则,即“不要打电话过来,我们会打给你”。