依赖倒置DIP+控制反转IOC+依赖注入DI
依赖倒置原则 - DIP, Dependence Inversion Principle
为软件设计六大设计原则之一,定义如下:
上层模块不应该依赖底层模块,它们都应该依赖于抽象。
抽象不应该依赖于细节,细节应该依赖于抽象。
上层模块不应依赖底层模块,即上层的业务模块不应该依赖底层的实现模块。如:人出行使用交通工具,只需要知道是交通工具就可以,不用知道是哪种具体的交通工具。
抽象不应该依赖于细节,细节应该依赖于抽象。在java编程中,抽象指代接口、抽象函数,统称为接口,而细节指代接口的具体实现。
因此,依赖倒置原则即为面向接口编程的原则。
示例:
交通工具类:
public interface Driveable {
void drive();
}
class Bike implements Driveable{
@Override
public void drive() {
// TODO Auto-generated method stub
System.out.println("Bike drive.");
}
}
class Car implements Driveable{
@Override
public void drive() {
// TODO Auto-generated method stub
System.out.println("Car drive.");
}
}
Person类:
public class Person {
private Driveable mDriveable;
public Person() {
mDriveable = new Train();
}
public void chumen() {
System.out.println("出门了");
mDriveable.drive();
}
}
Person中使用接口Driveable来定义交通工具,出行依赖的是交通工具接口,而不是具体的交通工具。这样,我们可以自由的选择交通工具,只要该交通工具实现该接口,并将其传递给Person类中的Driveable接口。 这就是面向接口编程的好处。
好处:可扩展性比较好,以后添加其他交通工具不影响现在代码。即抽象不依赖于细节。
控制反转 - IOC, Inversion of Control
问题:Person中还是需要创建具体交通工具,并用其初始化Driveable接口。
Person自己要负责创建具体交通工具,而且要关心交通工具创建成功与否。如果放在现实生活中,这是一件特别荒谬的事情。Person实际上只需要使用具体交通工具,制造厂才需要创建具体交通工具。对于Person来说,你只要提供给我交通工具,我使用就好了。这就引出了控制反转的概念,即Person不需要自己创建其依赖的交通工具,交通工具只需要在外面创建好,给Person就好了。
控制反转下Person类的实现:
public class Person {
private Driveable mDriveable;
public Person(Driveable driveable) {
mDriveable = driveable;
}
public void chumen() {
System.out.println("出门了");
mDriveable.drive();
}
}
使用Person类:
public class Test {
public static void main(String[] args) {
Train train = new Train();
Person person = new Person(train);
person.chumen();
}
}
这样,交通工具在创建Person的时候传递给Person类就好,完全解放了Person类。这样,出现新的交通工具,或需要改变Person使用的交通工具,都不需要修改Person类。
IoC, 控制反转是Spring框架中的一个重要思想,即依赖方不需要关心被依赖对象的创建,只需要使用传进来的被依赖对象即可。IoC结合面向接口编程,可以使得编写的程序扩展性更强。
依赖注入 - DI , Dependency Injection
依赖注入是实现控制反转的一个手段,通过配置文件xml,annotation-based或java-based的方式来实现,是Spring中的核心概念。 关于具体怎么实现DI,可以参考我之前的文章Spring - DI .