依赖注入(DI),控制反转(IOC),依赖反转(依赖倒置/DIP)

作为一个业余后端爱好者,虽然时不时会看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)。而我们通常称为面向接口编程,抽象之类的

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容