什么是依赖?
如果一个类A的功能实现要借助B,那么就叫B是A的依赖,则称作A依赖于B。比如说,一个人喜欢看视频,而他看视频需要借助手机来实现,则称他依赖于手机。
依赖倒置原则
- 上层模块不应该依赖底层模块,它们都应该依赖于抽象。
- 抽象不应该依赖于细节,细节应该依赖于抽象。
举个例子:
public class Person {
private Bike mBike;
public Person() {
mBike = new Bike();
}
public void chumen() {
System.out.println("出门了");
mBike.drive();
}
}
public class Test1 {
public static void main(String[] args) {
Person person = new Person();
person.chumen();
}
}
一个Person类,他有一个chumen()方法,Person依赖于Bike类,借助BIke来实现chumen()。
现在我们想换成Car作为交通工具。
public class Person {
private Bike mBike;
private Car mCar;
public Person() {
//mBike = new Bike();
mCar = new Car();
}
public void chumen() {
System.out.println("出门了");
//mBike.drive();
mCar.drive();
}
}这样,我们每次想要修改出门方式的时候,就要在Person类中修改大量的代码,当项目过于庞大时,会很难进行维护。我们应该遵循依赖倒置的原则。
即:上层模块应该依赖于抽象。
因此,定义一个接口。
public interface Driveable {
void drive();
}各种交通工具,Car,Bike等都来实现这个类。这是,Person类应该这样定义。
public class Person {
// private Bike mBike;
// private Car mCar;
// private Train mTrain;
private Driveable mDriveable;
public Person() {
//mBike = new Bike();
//mCar = new Car();
//mTrain = new Train();
mDriveable = new Train();
}
public void chumen() {
System.out.println("出门了");
//mBike.drive();
//mCar.drive();
//mTrain.drive();
mDriveable.drive();
}
}这样,当我们想要修改交通工具时,只需要修改 mDriveable = new Train();这一行代码即可。
上面的内容就是依赖倒置原则。
有人会考虑到倒置这个词,个人的理解是倒置是改变的意思。
本来正常编码下,肯定会出现上层依赖底层的情况,而依赖倒置原则的应用则改变了它们之间依赖的关系,它引进了抽象。上层依赖于抽象,底层的实现细节也依赖于抽象,所以依赖倒置我们可以理解为依赖关系被改变,如果非常纠结于倒置这个词,那么倒置的其实是底层细节,原本它是被上层依赖,现在它倒要依赖与抽象的接口。
控制反转
虽然,我们实现了依赖倒置,更改出行方式很方便,但是每次更改出行方式的时候,Person 这个类还是要修改。Person还是自己掌管着接口的实例化。这样,程序也就不方便维护。因此,我们将Person对Drivable的控制权剥离出来,交给第三方。
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) {
// TODO Auto-generated method stub
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();
}
}
这里我们相当于把控制权交给了Test1这个类。也就是说 Person 只关心依赖提供的功能,但并不关心依赖的创建。Person 不再亲自创建 Driveable 对象,它将依赖的实例化的权力交接给了 Test1。
把A对B的控制权抽离出来,将控制权交给第三方,这就是控制反转。依赖注入是控制反转最典型的实现方法。将控制权交给IOC容器,通过构造方法,属性或者工厂模式来将类B注入到A中。
依赖倒置是面向对象开发领域中的软件设计原则,它倡导上层模块不依赖于底层模块,抽象不依赖细节。依赖反转是遵守依赖倒置这个原则而提出来的一种设计模式,它引入了 IoC 容器的概念。依赖注入是为了实现依赖反转的一种手段之一。它们的本质是为了代码更加的“高内聚,低耦合”。