依赖倒置
原则:
1、上层模块不应该依赖底层模块,它们都应该依赖于抽象
2、抽象不应该依赖于细节,细节应该依赖于抽象
public class Person {// private Bike mBike;// private Car mCar;// private Train mTrain;private Driveable mDriveable;public Person() {mDriveable = new Train();}public void chumen() {System.out.println("出门了");//mBike.drive();//mCar.drive();//mTrain.drive();mDriveable.drive();}}
这里有一张人出门的照片,很形象:
依赖倒置实质上是面向接口编程的体现
控制反转(LOC)
上面的例子中需要person自己来实例化driver,而控制反转就是通过构造函数传入Driver,不管出行方式发生什么变化,person都不需要做改动。
public class Person {private Driveable mDriveable;public Person(Driveable driveable) {this.mDriveable = driveable;}public void chumen() {System.out.println("出门了");mDriveable.drive();}}public class Test1 {public static void main(String[] args) {Bike bike = new Bike();Car car = new Car();Train train = new Train();// Person person = new Person(bike);// Person person = new Person(car);Person person = new Person(train);person.chumen();}}
依赖注入
为了不因为依赖实现的变动而去修改 Person, 也就是说以可能在 Driveable 实现类的改变下不改动 Person 这个类的代码,尽可能减少两者之间的耦合。我们需要采用上一节介绍的 IoC 模式来进行改写代码.
这个需要我们移交出对于依赖实例化的控制权,那么依赖怎么办?Person 无法实例化依赖了,它就需要在外部(IoC 容器)赋值给它,这个赋值的动作有个专门的术语叫做注入(injection),需要注意的是在 IoC 概念中,这个注入依赖的地方被称为 IoC 容器,但在依赖注入概念中,一般被称为注射器 (injector)。
实现依赖注入有3种方式:
- 构造函数中注入
- setter方式注入
- 接口注入
setter注入:
public class Person {public void setDriveable(Driveable mDriveable) {this.mDriveable = mDriveable;}}
接口方式注入:
public interface DepedencySetter {void set(Driveable driveable);}class Person implements DepedencySetter{private Driveable mDriveable;@Overridepublic void set(Driveable driveable) {this.mDriveable = mDriveable;}}
在软件框架中,读取xml配置文件,或者是利用反射技术读取注解,然后根据配置信息,框架动态将一些依赖配置给特定接口的类,我们也可以说injector也依赖于接口,而不是特定的实现类,这样更进一步的提高了准确性与灵活性。
总结
- 控制反转是设计模式,遵从了依赖倒置的原则
- 依赖注入是实现控制反转的手段
- 本质是为了代码更加的“高内聚,低耦合”
- 控制反转是遵守依赖倒置这个原则而出来的一种设计模式,它引入了loc容器的概念。
在知乎上看到别人写的回答,感觉很形象
设计模式
