版主: Bellaa
昵称:贝拉拉
等级:
Lv.98 
经验
9880
金币
33.20万
积分
1339
 发表于 2021-08-17 22:35  查看 806 | 倒序浏览
依赖注入解析

生活举例来说,人只能借助钓竿才能达到钓鱼的目的,这种情况就说人依赖钓竿。

程序语言来说,人是类,钓竿是类,钓鱼是钓竿的方法,如果人想完成钓鱼活动,只能将钓竿作为自己的成员然后调用钓竿的钓鱼方法,下图代码中People类便依赖NormalFishRod类。



引用是什么
引用指的是上述代码的normalFishRod,对象指的是new FishRod();方法生成的实例。笔者当初就是这个没弄明白,走了很多弯路。

依赖倒置 (Dependency inversion principle)
概念:
高层模块不应该依赖低层模块,他们应该依赖底层模块的抽象类或者接口。

三个点:
高层模块与低层模块是什么
在我的钓鱼demo中,需求关系是这样的,人需要用到钓竿而不是钓竿需要用到人,所以人是高层模块,钓竿是低层模块。

高层模块依赖低层模块的抽象或接口是什么
在依赖概念中我们已经知道了,类依赖的是别的类的引用,图1中代码描绘People依赖具体的一种钓竿NormalFishRod。而钓竿除了NormalFIshRod还有GoodFishRod,他们的依赖关系如图。

人直接依赖低层模块,即依赖具体的钓竿类型,这不符合依赖低层模块的抽象原则。

钓竿应该是可以抽象的,因为好钓竿和差钓竿都有共同的方法钓鱼。

所以把依赖关系改成下图中这种,钓竿是抽象类或者接口,而普通钓竿和好钓竿都实现了这个接口,然后人持有钓竿这个抽象类的引用,这样就达到了人依赖抽象类或接口,而具体类也依赖抽象类的目的。



为什么普通钓竿依赖钓竿类
引用群里老哥一句话,你把接口去掉,那实现类会不会报错,会的吧,这就说明实现类是依赖接口的。

在软件开发过程中,依赖通常有三种体现形式:

1、将一个类的对象作为另一个类中方法的参数

2、在一个类的方法中将另一个类的对象作为其局部变量

3、在一个类的方法中调用另一个类的静态方法。而这并不绝对,比如实现接口的类也依赖接口,这也算的。


未使用依赖倒置时候代码为:


使用依赖倒置原则后代码为:

控制反转 (IoC)
概念
控制反转 IoC 是 Inversion of Control的缩写,字面意思即为控制权的反转。

控制反转就是将创建实例化的权利从上层模块(即我例子中的人类)转移。把所依赖成员的实例化创建工作交由IOC容器完成而非自己亲自完成。下面用我钓鱼的例子来解释一下使用与不使用的时候两者差别。使用控制反转前:钓竿在People类中完成创建(即new NormalFIshRod()语句),看上图的diaoyuActive()。

使用控制反转之后:钓竿引用的实例化不在People类中完成,而是在外部完成并传入People类中赋值给钓竿的引用fishRod。传入的方式是这样的,传入途径有多种,而传入其中并赋值给引用的过程就叫做,依赖注入,依赖注入,依赖注入,重要事情说三遍。我们需要知道的是控制反转的本质是将成员实例化交给另一个容器进行创建,而非自己来完成,这个容器叫做IOC容器,怎么确定谁是IOC容器,new语句在哪个地方,哪个地方就是IOC容器,如下图所示,MainTest其实就是IOC容器,因为实例化创建在其中完成。


总结
总结控制反转与依赖注入的关系就是。我是人类,我有个锤子类成员,但我可不想自己生产一个锤子,所以我得靠别人生产锤子,并送到我手上,我只负责使用就好了,而制造锤子并给我的那个地方很洋气,叫我IOC容器,而IOC容器把锤子交给我的过程,叫做依赖注入,交给我的方式有很多,下面我们一一分析依赖注入这个概念。

依赖注入(Dependency injection)
定义
依赖注入,也称为 DI,完成控制反转大体可以分为如下两步:

1、创建实例化

2、将实例化注入相应类属性中(把鱼竿注实例并注入人类中的鱼竿引用)

依赖注入指的是第二步的工作。

实现
实现依赖注入大体有下三种方式:

通过构造函数注入
通过set方法注入
通过接口方式进行注入
三种注入方式代码如下:

接口注入的意义:
只有实现了接口的类才能进行注入,那么就可以控制那些类可以注入哪些类不可以注入了。就像人类有很多子类,有些子类是不能钓鱼的,比如说小朋友,因为河边危险嘛,我们不应该开放发放钓竿的方法给小朋友,所以小朋友不实现该接口即可。

源代码:
interface DepedencySetter {
   void set(FishRod fishRod);
}

class People implements DepedencySetter{
   private FishRod fishRod;

   public People(FishRod fishRod) {
      this.fishRod = fishRod;
   }

   public void setFishRod(FishRod fishRod) {
      this.fishRod = fishRod;
   }

   @Override
   public void set(FishRod fishRod) {
      this.fishRod = fishRod;
   }

   public void diaoyuActive() {
      fishRod = new NormalFishRod();
      fishRod.diaoyu();
   }
}

interface FishRod {
   void diaoyu();
}

class NormalFishRod implements FishRod {
   public void diaoyu() {
      System.out.println("普通竿钓鱼");
   }
}

class GoodFishRod implements FishRod {
   public void diaoyu() {
      System.out.println("好竿钓鱼");
   }

}

class MainTest {
   public static void main(String[] args) {
      FishRod fishRod = new NormalFishRod();
      People people = new People(fishRod);
      
   }
}

————————————————
版权声明:本文为CSDN博主「TesuZer」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/TesuZer/java/article/details/80816233
沙发:  noob
昵称:代号9527
等级:
Lv.39 至尊
经验
1639
金币
34.62万
积分
573
  发表于:2020-04-24 15:34
多谢楼主分享,很不错的讲解
板凳: studio
昵称:qgtstudio
等级:
Lv.158 
经验
2.51万
金币
8067
积分
2705
  发表于:2021-08-27 10:06
谢谢楼主分享
快速回帖