Java 中的依赖注入模式:通过松耦合提高可维护性
大约 3 分钟
也称为
- 控制反转 (IoC)
- 依赖倒置
依赖注入设计模式的意图
将对象依赖的创建与使用解耦,从而实现更灵活和可测试的代码。
依赖注入模式的详细解释及真实世界示例
真实世界示例
想象一家高档餐厅,厨师需要各种食材来烹饪菜肴。厨师不会亲自去不同的供应商那里获取每种食材,而是由一个值得信赖的供应商每天提供所有需要的鲜货。这使得厨师可以专注于烹饪,而不必担心食材的来源。
在依赖注入设计模式中,值得信赖的供应商充当“注入器”,为厨师(对象)提供必要的依赖项(食材)。然后,厨师可以使用这些依赖项,而无需了解它们的来源,确保了依赖项创建和使用之间的清晰分离。这种设置提高了厨房的效率、灵活性和可维护性,就像在软件系统中一样。
通俗地讲
依赖注入将客户依赖项的创建与客户自身的行为分离。
维基百科说
在软件工程中,依赖注入是一种技术,其中一个对象接收它所依赖的其他对象。这些其他对象被称为依赖项。
Java 中依赖注入模式的编程示例
老巫师喜欢偶尔装满他的烟斗并抽烟草。然而,他不想只依赖一个烟草品牌,而是希望能够随意享受所有品牌。
首先,让我们介绍Tobacco
接口和具体的品牌。
@Slf4j
public abstract class Tobacco {
public void smoke(Wizard wizard) {
LOGGER.info("{} smoking {}", wizard.getClass().getSimpleName(),
this.getClass().getSimpleName());
}
}
public class SecondBreakfastTobacco extends Tobacco {
}
public class RivendellTobacco extends Tobacco {
}
public class OldTobyTobacco extends Tobacco {
}
接下来是Wizard
类层次结构。
public interface Wizard {
void smoke();
}
public class AdvancedWizard implements Wizard {
private final Tobacco tobacco;
public AdvancedWizard(Tobacco tobacco) {
this.tobacco = tobacco;
}
@Override
public void smoke() {
tobacco.smoke(this);
}
}
最后,我们可以展示为老巫师提供任何品牌的烟草是多么容易。
public static void main(String[] args) {
var simpleWizard = new SimpleWizard();
simpleWizard.smoke();
var advancedWizard = new AdvancedWizard(new SecondBreakfastTobacco());
advancedWizard.smoke();
var advancedSorceress = new AdvancedSorceress();
advancedSorceress.setTobacco(new SecondBreakfastTobacco());
advancedSorceress.smoke();
var injector = Guice.createInjector(new TobaccoModule());
var guiceWizard = injector.getInstance(GuiceWizard.class);
guiceWizard.smoke();
}
程序输出
11:54:05.205 [main] INFO com.iluwatar.dependency.injection.Tobacco -- SimpleWizard smoking OldTobyTobacco
11:54:05.207 [main] INFO com.iluwatar.dependency.injection.Tobacco -- AdvancedWizard smoking SecondBreakfastTobacco
11:54:05.207 [main] INFO com.iluwatar.dependency.injection.Tobacco -- AdvancedSorceress smoking SecondBreakfastTobacco
11:54:05.308 [main] INFO com.iluwatar.dependency.injection.Tobacco -- GuiceWizard smoking RivendellTobacco
依赖注入模式的详细解释及真实世界示例

何时在 Java 中使用依赖注入模式
- 当旨在减少类之间的耦合并提高应用程序的模块化时。
- 在对象创建过程很复杂或应该与类使用分离的情况下。
- 在需要更轻松地进行单元测试的应用程序中,允许对依赖项进行模拟或存根。
- 在管理对象生命周期和依赖项的框架或库中,例如 Spring 或 Jakarta EE(以前称为 Java EE)。
Java 中依赖注入模式的真实世界应用
- Spring、Jakarta EE 和 Google Guice 等框架广泛使用依赖注入 (DI) 来管理组件生命周期和依赖项。
- 需要灵活架构且组件易于互换的桌面和 Web 应用程序。
依赖注入模式的优缺点
优点
- 增强模块化和关注点分离。
- 通过允许轻松模拟依赖项来简化单元测试。
- 通过促进松耦合来提高灵活性 and 可维护性。
权衡
- 可能会在配置中引入复杂性,尤其是在大型项目中。
- 可能会增加不熟悉依赖注入模式或框架的开发人员的学习曲线。
- 需要仔细管理对象生命周期和作用域。
相关的 Java 设计模式
- 工厂方法 和 抽象工厂:用于创建 DI 机制将注入的实例。
- 服务定位器:一种替代 DI 的方法,用于定位服务或组件,但它不像 DI 那样有效地解耦查找过程。
- 单例:通常与 DI 结合使用,以在整个应用程序中提供服务的单个实例。