什么是依赖(Dependency)?
依赖是类与类之间的连接,依赖关系表示一个类依赖于另一个类的定义,通俗来讲就是一种需要,例如一个人(Person)可以买车(Car)和房子(House),Person类依赖于Car类和House类
static class People {
// 依赖house
public void buy(House house) {
}
//依赖car
public void buy(Car car) {
}
}
static class House {
}
static class Car {
}
依赖倒置(Dependency inversion principle)
依赖倒置是面向对象设计领域的一种软件设计原则软件设计有6大设计原则,合称SOLID
1、单一职责原则(Single Responsibility Principle,简称SRP)
- 核心思想:应该有且仅有一个原因引起类的变更
2、里氏替换原则(Liskov Substitution Principle,简称LSP)
- 核心思想:在使用基类的的地方可以任意使用其子类,能保证子类完美替换基类。
3、依赖倒置原则(Dependence Inversion Principle,简称DIP)
- 核心思想:高层模块不应该依赖底层模块,二者都该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象;
4、接口隔离原则(Interface Segregation Principle,简称ISP)
- 核心思想:类间的依赖关系应该建立在最小的接口上
5、迪米特法则(Law of Demeter,简称LoD)
- 核心思想:类间解耦。通俗来讲:一个类对自己依赖的类知道的越少越好。
6、开放封闭原则(Open Close Principle,简称OCP)
什么是上层模块和底层模块?
公司管理层就是上,CEO是整个事业群的上层,那么CEO职能之下就是底层。然后,我们再以事业群为整个体系划分模块,各个部门经理以上部分是上层,那么之下的组织都可以称为底层。
由此,我们可以看到,在一个特定体系中,上层模块与底层模块可以按照决策能力高低为准绳进行划分。
那么,映射到我们软件实际开发中,一般我们也会将软件进行模块划分,比如业务层、逻辑层和数据层。
业务层中是软件真正要进行的操作,也就是做什么。
逻辑层是软件现阶段为了业务层的需求提供的实现细节,也就是怎么做。
数据层指业务层和逻辑层所需要的数据模型。
因此,如前面所总结,按照决策能力的高低进行模块划分。业务层自然就处于上层模块,逻辑层和数据层自然就归类为底层。
什么是抽象和细节?
象如其名字一样,是一件很抽象的事物。抽象往往是相对于具体而言的,具体也可以被称为细节,当然也被称为具象。
比如:
- 这是一幅画。画是抽象,而油画、素描、国画而言就是具体。
- 这是一件艺术品,艺术品是抽象,而画、照片、瓷器等等就是具体了。
- 交通工具是抽象,而公交车、单车、火车等就是具体了。
- 表演是抽象,而唱歌、跳舞、小品等就是具体。
上面可以知道,抽象可以是物也可以是行为。
具体映射到软件开发中,抽象可以是接口或者抽象类形式。
控制反转(IoC)
控制反转IoC是Inversion of Control的缩写,意思就是对于控制权的反转,对么控制权是什么控制权呢?
Person自己掌控着内部mDriveable的实例化。
现在,我们可以更改一种方式。将mDriveable的实例化移到Person外面。
class People {
private Drivable mDrivable;
public People(Drivable mDrivable) {
this.mDrivable = mDrivable;
}
public void goOut() {
System.out.println("go out");
mDrivable.drive();
}
}
class Drivable {
public void drive() {
}
}
就这样无论出行方式怎么变化,Person这个类都不需要更改代码了。
这种思想其实就是IoC,IoC是一种新的设计模式,它对上层模块与底层模块进行了更进一步的解耦。控制反转的意思是反转了上层模块对于底层模块的依赖控制。
比如上面代码,Person不再亲自创建Driveable对象,它将依赖的实例化的权力交接给了调用的类。而Person在IoC中又指代了IoC容器这个概念。
依赖注入(Dependency injection)
依赖注入,也经常被简称为DI,其实在上一节中,我们已经见到了它的身影。它是一种实现IoC的手段。什么意思呢?
为了不因为依赖实现的变动而去修改Person,也就是说以可能在Driveable实现类的改变下不改动Person这个类的代码,尽可能减少两者之间的耦合。我们需要采用上一节介绍的IoC模式来进行改写代码。
这个需要我们移交出对于依赖实例化的控制权,那么依赖怎么办?Person无法实例化依赖了,它就需要在外部(IoC容器)赋值给它,这个赋值的动作有个专门的术语叫做注入(injection),需要注意的是在IoC概念中,这个注入依赖的地方被称为IoC容器,但在依赖注入概念中,一般被称为注射器(injector)。
表达通俗一点就是:我不想自己实例化依赖,你(injector)创建它们,然后在合适的时候注入给我
实现依赖注入有3种方式:
- 构造函数中注入
- setter方式注入
- 接口注入