在依赖注入环境(如 Spring Boot)中创建设计模式是不是无用?
Posted
技术标签:
【中文标题】在依赖注入环境(如 Spring Boot)中创建设计模式是不是无用?【英文标题】:Are creational design patterns useless in Dependency Injection environment ( like SpringBoot)?在依赖注入环境(如 Spring Boot)中创建设计模式是否无用? 【发布时间】:2021-10-30 09:13:00 【问题描述】:我正在研究设计模式,有一次我突然想到,像工厂和抽象工厂这样的大多数创建模式在依赖注入环境的范围内并不是那么有用,在这种环境中,我们通常不会使用new
关键字,但从某些上下文中“注入”它们。我也明白我很可能是错的,我需要一个很好的解释来说明问题。
【问题讨论】:
【参考方案1】:你没有错。 GoF 书中有五种创建模式,作为 Java 开发人员,您可能永远不会使用其中任何一种。
-
Abstract Factory - 依赖注入当然会减少(如果不是消除)对这种模式的需求。 Service Locator is an Anti-Pattern 是公认的,如果您进一步询问 Is the Service Locator pattern any different from the Abstract Factory pattern?,答案是,不是。
Builder 是一种您可能在 Java 中使用的模式,但不是 GoF 书中的版本。作为一名 Java 开发人员,您很可能会从 Effective Java 实现 Josh Bloch 的版本(或者让 Lombok 为您实现它)。见:How to implement the Builder Design Pattern in the right way?
工厂方法 只是模板方法模式的创建版本。虽然这仍然是一个有用的模式,但它基本上是基于继承的;我们现在都知道prefer composition over inheritance。
原型是一种高度特定于语言的模式。在其他语言中,这是至关重要的。在Java中,没有那么多。 Prototype pattern is not a useful performance tool in Java 和 Spring 实现的 Prototype bean 生活方式是 not equivalent 到 GoF 模式。
Singleton 是 divisive,即使在 GoF 中也是如此。今天,它被广泛认为是一种反模式。您更有可能使用 Spring 实现的 Singleton bean 生活方式,这(再次)是 not equivalent 到 GoF 模式。
【讨论】:
我真的很矛盾是否要投票。服务定位器与抽象工厂完全不同。抽象工厂主要处理构建相关的对象族,并且与 Builder(GOF 之一,而不是 Bloch 的构建器)结合使用非常有用。服务定位器处理依赖查找,而抽象工厂通常以相反的方式使用,与 DI .工厂方法的继承对应部分是“简单工厂”或“常规类工厂”,抽象工厂的第一个产品版本。 服务定位器和抽象工厂是实现Dependency Inversion without Inversion of Control的两种机制。从 IoC 是理想的角度来看,它们都是不可取的,而且它们都没有实现。 @jaco0646 感谢您为我澄清这一刻,因为我看到您提到了在 DI 环境中不太有用的模式,您能否提供一个有用的列表? @MisaD。如果你想做 OOP,你应该对利用组合的模式有很强的把握。例如,装饰器和适配器是 OOP 中简单、普遍存在的模式。从行为模式的范畴来看,Observer 是一个非常强大但未被充分利用的设计。【参考方案2】:使用 依赖注入 / 控制反转 框架(例如 Spring)确实减少了对四组创建模式的需求,但可能无法消除它们。
首先,让我们注意到 Spring 支持一个名为“Singleton”的作用域(实例创建模式)。虽然它的实施与 GOF 建议的不同,但许多想法是相同的。在这种情况下,如果 Spring 在您的项目中普遍存在,您将不需要 GOF 单例。如其他地方所述,开发人员应警惕滥用单例,因为单例可能导致静态、不可测试和不可配置的代码。
接下来,抽象工厂用于创建整个系列的相关产品。 GOF 书中甚至没有提到 1 产品简化类型。我想他们认为它已经太出名了。在 Spring 环境中,您通常会使用 Spring 来注入您需要的产品,而不是通过工厂创建它,但在某些情况下,您会改为注入工厂,然后从中创建产品!
原型是另一个令人困惑的问题。 GOF 模式很少用在具有反射的语言中,因为它们确实有其他方法,尽管不一定是创建对象副本的更好方法。令人困惑的一点是 Spring 使用“原型”这个词来表示一个不是单例的 Bean,我猜是因为他们最初假设这个 Bean 的所有新实例基本上都以相同的方式开始。
工厂方法通常在框架中使用,在应用程序级代码中较少使用。当框架选择创建对象时,它让框架的用户决定创建什么样的对象。 Spring 实际上做了一些非常相似但没有继承的事情。当你将一个函数标记为@Bean 时,Spring 在它想要创建一个新实例时调用你的函数,将 Factory Method 的继承机制替换为 Spring 的反射和拦截。
【讨论】:
在什么情况下你会注入一个抽象工厂而不是它的产品? 一个例子是当您需要多个实例时。一种常见的做法是注入 EntityManagerFactory,以便您可以为特定的持久性单元创建 EntityManager。【参考方案3】:像 Spring 这样的 DI 框架会初始化和管理 bean。创建模式可用于创建领域(业务)对象。
【讨论】:
以上是关于在依赖注入环境(如 Spring Boot)中创建设计模式是不是无用?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 Spring Boot 将来自 Google Secret Manager 的秘密作为环境变量注入 Kubernetes Pod?
在 Spring Boot 中创建名为“batchConfigurer”的 bean 时出错