java - 依赖注入(inject)、多态性和 OOP 模式(MVC、命令等)

标签 java oop jakarta-ee design-patterns dependency-injection

简介:我使用 Java EE 7 和 glassfish 4(因此 CDI 容器是焊接的)。这是我阅读有关依赖注入(inject)及其原理的第三天,所以如果你觉得我的问题很愚蠢,请解释一下我的误解....这个问题来自 How to implement command pattern via CDI?

问题: 读了四本书。我认为 DI 是一项很好的技术,它使我们的代码清晰。

我看到的两个主要原则是: 第一个主要原则 - CDI 容器注入(inject)某些类的实例。第二个主要原则是“记住:“只能有一个。”(焊接引用 (WR))。

所以当我们开始积极使用多态时,问题就出现了。我不知道其他人如何做 MVC,但我有很多 Controller 。此外,我想尝试新的设计并将所有应用程序划分为组件,每个组件都有其 Controller 和操作。理想情况下,每个组件都可以由独立的程序员开发。当我们不使用 CDI 时一切正常。每个组件都有其 Controller 和操作。例如 10 个组件可以有 SaveAction 类。很明显,这些类是私有(private)的,只能在它们的包中使用。在这里我们有一个大问题。我们必须清楚地区分我们想要使用的 Action 类实例(来自实现此接口(interface)的所有类)。

来自 WR:

要修复不明确的依赖关系,可以:

  • introduce a qualifier to distinguish between the two implementations of the bean type,
  • disable one of the beans by annotating it@Alternative,
  • move one of the implementations to a module that is not in the classpath of the module with the injection point, or
  • disable one of two @Alternative beans that are trying to occupy the same space, usingbeans.xml.

如果我使用几十个 Action 类,我该如何遵循这些建议?我尝试使用生产者方法。但是没有新的(新的我们不能使用,否则 Controller 和 Action 不能注入(inject)其他bean)。在这种情况下,Weld 说要这样做。

@Produces @Preferred @SessionScoped
public PaymentStrategy getPaymentStrategy(CreditCardPaymentStrategy ccps,
    CheckPaymentStrategy cps,PayPalPaymentStrategy ppps) {
    switch (paymentStrategy) {
       case CREDIT_CARD: return ccps;
       case CHEQUE: return cps;
       case PAYPAL: return ppps;
       default: return null;
    }
}

问题:我在这里看到三个变体。

  1. 我对 CDI 的理解是否有误?
  2. 这项技术(在此实现中)是否非常有限?
  3. 存在解决方案,但我没有看到?

请告诉我正确的方法。

最佳答案

我认为您的答案非常接近正确,除非您似乎想要一个更通用的解决方案。在 CDI 中处理它的一种方法是确保命名 PaymentStrategy 的每个实现。然后我会这样改变你的生产者的实现:

@Produces @Preferred @SessionScoped
public PaymentStrategy getPaymentStrategy(Instance<PaymentStrategy> myInstance) {
  String paymentStrategy = ...;  // Get the name of the payment strategy needed right now

   return myInstance.select(new NamedImpl(paymentStrategy));
}

此解决方案的关键部分是传入的实例(请参阅 http://docs.oracle.com/javaee/6/api/javax/enterprise/inject/Instance.html)。该实例将包含 PaymentStrategy 的每个实现。然后,您可以根据您选择的任何标准选择正确的。在上面的示例中,我选择了名称,但您也可以选择限定符,或者您可以遍历所有实现并使用您自己设计的其他一些标准来根据情况选择正确的标准。

下面是 NamedImpl 的实现(我在上述解决方案中使用的 AnnotationLiteral,以便选择具有正确名称的服务):

public class NamedImpl extends AnnotationLiteral<Named> implements Named {
    private final String name;

    public NamedImpl(String name) {
        this.name = name;
    }

    @Override
    public String value() {
        return name;
    }

    public String toString() {
        return "@Named(" + name + ")";
    }

}

我会注意到,我相信 HK2 有一个更好的版本 https://hk2.java.net/apidocs/org/glassfish/hk2/api/IterableProvider.html因为它允许您将更多元数据与您的服务相关联,并且具有像命名这样的辅助函数。由于您使用的是 GlassFish 4,因此您还可以评估 HK2,因为 CDI 和 HK2 在 GlassFish 4 中很好地集成在一起。

关于java - 依赖注入(inject)、多态性和 OOP 模式(MVC、命令等),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20176672/

相关文章:

c++ - OOP设计:一个对象依赖于其所有依赖项的存在

java - JAVA 如何将构造函数中的值传递给另一个类中的 setter?

java - 在jsp页面中显示特殊字符

java - 将 Servlet 链接到选项卡菜单

java - Java 的标准输入文件格式和解析器?

java - java计算数组中的重复次数

php - 在php中实现不同用户级别的 View

java - 如何超越LogManager警告?

java - 如何调用属于某个 Activity 的 fragment 的方法

java - 在构造期间抛出异常后清理