也称为控制反转 (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 结合使用,以在整个应用程序中提供服务的单个实例。参考资料和鸣谢代码整洁之道:敏捷软件开发手册依赖注入:使用 Spring 和 Guice 的设计模式依赖注入原则、实践和模式Google Guice:敏捷轻量级依赖注入框架Java 9 依赖注入:使用 Spring 5 和 Guice 编写松耦合代码Java 设计模式精要精通 Java EE Spring 模式:使用 Spring 框架实施 Java EE 模式的最佳实践和设计策略Spring 实战