1.什么是依赖(Dependency)?
依赖是一种关系,通俗来讲就是一种需要。
比如
class Shopper {
FoodA mFoodA;
public Shopper() {
mFoodA = new FoodA();
}
}
Shopper 的内部持有 FoodA 的引用,这就是依赖在编程世界中的体现。
2.依赖倒置(DIP)
定义
- 上层模块不应该依赖底层模块,它们都应该依赖于抽象。
- 抽象不应该依赖于细节,细节应该依赖于抽象。
还是以上面的商家拥有食物的例子来说.通常一个商家不止一种,可能还有FoodB
class Shopper {
//FoodA mFoodA;
FoodB mFoodB;
public Shopper() {
//mFoodA = new FoodA();
mFoodB = new FoodB();
}
}
甚至会有FoodC,FoodD等等.问题是每次我们都要去改Shoper类么?当然不是,我们可以引入抽象
interface Food {
void printFoodName();
}
class FoodA implements Food {
@Override
public void printFoodName() {
System.out.println("FoodA");
}
}
class FoodB implements Food {
@Override
public void printFoodName() {
System.out.println("FoodB");
}
}
这样一来,Shopper就简单多了(当然,此时还是需要改动的)
class Shopper {
Food mFood;
public Shopper() {
mFood = new FoodB();// 想要哪种就配哪种
}
public void print() {
mFood.printFoodName();
}
}
3.控制反转 (IoC)
控制权放外面(本来由Shopper来决定Food的种类,现在可以放在外面,让业务来决定)这样一来,就算Food种类有变化,依然不需要去改Shopper的代码
显然,上面的例子还没做到
4.依赖注入(Dependency injection)
依赖注入,也经常被简称为 DI,它是一种实现 IoC 的手段。
实现依赖注入有 3 种方式:
1.构造函数中注入
class Shopper {
Food mFood;
public Shopper(Food food) {
mFood = food;
}
public void print() {
mFood.printFoodName();
}
}
优点:在 Shopper 一开始创建的时候就确定好了依赖。
缺点:后期无法更改依赖。
2.setter 方式注入
class Shopper {
Food mFood;
public void setFood(Food food) {
mFood = food;
}
public void print() {
if(mFood != null) {
mFood.printFoodName();
}
}
}
优点:Shopper 对象在运行过程中可以灵活地更改依赖。
缺点:Shopper 对象运行时,可能会存在依赖项为 null 的情况,所以需要检测依赖项的状态。
3. 接口注入
interface Owner {
void setFood(Food food);
}
class Shopper implements Owner {
Food mFood;
@Override
public void setFood(Food food) {
mFood = food;
}
public void print() {
if(mFood != null) {
mFood.printFoodName();
}
}
}
和set注入很像?那么加入一个接口是不是多此一举呢?
答案肯定是不是的,这涉及到一个角色的问题。除了Shopper可以设置food以外,顾客也可以选择food啊
接口的存在,表明了一种依赖配置的能力。
网友评论