作为一个业余后端爱好者,虽然时不时会看spring和laravel的文档,但是一直对依赖注入和控制反转无法形成自己的理解。今天无意中又查找了些资料,有了新的理解。发现之前我想复杂了,因为spring和laravel对于依赖注入和控制反转的设计已经很完善,所以很难去抽丝剥茧依赖注入和控制反转到底是什么东西。
正文开始
- 假如我们现在要写一个“人”类,我们在“人”类里面有一个 “生成人头” 的方法, 下面是我们最初的样子
class Person{
String hairColor;
String eyeColor;
function generateHead(){
hairColor = "green";
eyeColor = "yellow";
}
}
- 后来我们通过简单的面向对象思维,把它单独交给一个头类Head来完成
class Head{
String hairColor;
String eyeColor;
__construct(String hColor, String eColor){
hairColor = hColor;
eyeColor = eColor;
}
}
class Person{
Head head;
function generateHead(){
head = new Head(hairColor: "green", eyeColor: "yellow");
}
}
- 但是我们的头类依然在生成头方法中去初始化,这很不灵活,所以我们在生成头的方法中设置一个“头”这个参数,允许从外部传入“头”
class Head{
String hairColor;
String eyeColor;
__construct(String hColor, String eColor){
hairColor = hColor;
eyeColor = eColor;
}
}
class Person{
Head head;
function generateHead(Head h){
head = h;
}
}
class PersonFactory{
makePerson(){
Head a = new Head(hairColor: "green", eyeColor: "yellow");
Person p = new Person();
p.generateHead(a);
}
}
这时候已经完成了控制反转,这里的控制指的是“初始化这个头”的操作,反转指的是“进行这个操作的地点发生了变化”。
之前是在“人”类里面完成,现在是谁调用方法,谁完成,这就是控制反转。
而方法传参属于依赖注入的其中一种方式,这里我们通过依赖注入实现了控制反转。
QA
那我们实际在laravel或者spring框架中见到的实现方式为什么不是这个样子呢?
因为框架中使用IOC容器,实现了自动依赖注入,所以不用再像我们这般去进行手动依赖注入的操作。
好了,到这里依赖注入和控制反转就讲完了,是不是很简单的一个东西,其实这只是面向对象思维中,关于一个具体的实现细节的规定,平时可能大家都在使用这种规则,但当专门拿出来说这是什么的时候,我们并不能把名字和操作细节对应上,但其实是很简单的一个概念,而我们很多时候称这类操作为“组合”,“工厂模式”
现在新的挑战出现了,当我们要使用生成头的时候,我们只能生成固定样式地头,假如有一天我们想让人长一个“铁头”,“鸡头”,“乌龟头”的时候,我们就需要去修改Person类,这是耦合的表现,所以依赖反转(依赖倒置/DIP)思维出现了
Interface Head{
setColors(String hColor, String eColor);
}
class IronHead implement Head{
String hairColor;
String eyeColor;
setColors(String hColor, String eColor){
hairColor = hColor;
eyeColor = eColor;
}
breakDoor(){
}
}
class ChickenHead implement Head{
String hairColor;
String eyeColor;
setColors(String hColor, String eColor){
hairColor = hColor;
eyeColor = eColor;
}
crow(){
}
}
class TurtleHead implement Head{
String hairColor;
String eyeColor;
setColors(String hColor, String eColor){
hairColor = hColor;
eyeColor = eColor;
}
makeYouCry(){
}
}
class Person{
Head head;
function generateHead(Head h){
head = h;
}
}
class PersonFactory{
makeIronPerson(){
Head a = new IronHead(hairColor: "green", eyeColor: "yellow");
Person p = new Person();
p.generateHead(a);
}
makeChickenPerson(){
Head a = new ChickenHead(hairColor: "yellow", eyeColor: "brown");
Person p = new Person();
p.generateHead(a);
}
makeTurtlePerson(){
Head a = new TurtleHead(hairColor: "yellow", eyeColor: "brown");
Person p = new Person();
p.generateHead(a);
}
}
好了,现在我们想创造不同头的人,不再需要依赖修改Person类了,只需要添加一个想要的头实现Head接口,然后直接组装就可以了。这里我们选择依赖抽象的接口Head,而不是具体的实现,这就是依赖反转(依赖倒置/DIP)。而我们通常称为面向接口编程,抽象之类的
网友评论