【问题标题】:Alternative CDI approach to subclassing?子类化的替代 CDI 方法?
【发布时间】:2021-02-05 14:00:06
【问题描述】:

这是我目前的工作代码:

public enum Year 
{
    year2021,
    year2022;
}

_

public class Zoo 
{
    private Year year;
    
    public Zoo(Year year)
    {
        this.year = year;
    }
    
    public int predictNumberOfAnimals() { ... }
}

_

@Qualifier
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.TYPE, ElementType.PARAMETER})
public @interface YearAnnotation 
{
    String value();
}

_

public class Zoo2021 extends Zoo
{
    @Inject 
    public Zoo2021(@YearAnnotation("y2021") Year year)
    {
        super(year);
    }
    
    @Produces @YearAnnotation("y2021")
    public static Year getYear()
    {
        return Year.year2021;
    }
}

_

public class Zoo2022 extends Zoo
{
    @Inject 
    public Zoo2022(@YearAnnotation("y2022") Year year)
    {
        super(year);
    }
    
    @Produces @YearAnnotation("y2022")
    public static Year getYear()
    {
        return Year.year2022;
    }
}

然后这个工作:

public class Client
{
    @Inject 
    private Zoo2022 zoo2022;
    
    @Inject 
    private Zoo2021 zoo2021;
}

但是,我不喜欢为每个新的Year 创建一个Zoo 的子类。假设不能将Year 作为参数传递给predictNumberOfAnimals

是否可以避免子类化并执行以下操作?:

public class Zoo 
{
    private Year year;
    
    @Inject
    public Zoo(Year year)
    {
        this.year = year;
    }
    
    public int predictNumberOfAnimals() { ... }
}

_

pulic class Client
{
    @Inject @YearAnnotation("y2021") // <- (*)
    private Zoo zoo2021;
    
    @Inject @YearAnnotation("y2022") // <- (*)
    private Zoo zoo2022;

    @Produces @YearAnnotation("y2021")
    public static Year getYear2021()
    {
        return Year.year2021;
    }
    
    @Produces @YearAnnotation("y2022")
    public static Year getYear2022()
    {
        return Year.year2022;
    }
}

使用(*) 处的@YearAnnotation 注释我想表明,在创建相应的Zoo 实例时,应注入相应的(不同的)年份(通过Zoo 的构造函数)。我的想法是以某种方式将@Produces 方法绑定到实例变量。

这样的事情可能吗?

【问题讨论】:

    标签: java dependency-injection cdi


    【解决方案1】:

    您可以简单地在生产者方法中获取注入点,从那里评估注解,并根据注解的值初始化具体对象。请注意,在这种情况下,注释中的具体值需要是非绑定的:

    @Qualifier
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.FIELD, ElementType.METHOD, ElementType.TYPE, ElementType.PARAMETER})
    public @interface YearAnnotation 
    {
        @Nonbinding
        String value();
    }
    

    生产者方法:

    @Produces @YearAnnotation Zoo makeZoo(InjectionPoint ip) {
        String yearValue = ip.getAnnotated().getAnnotation(YearAnnotation.class).value();
        ... create zoo, init with yearValue, return
    }
    

    就像你已经发布的那样注入

    @Inject @YearAnnotation("y2021")
    private Zoo zoo2021;
    
    @Inject @YearAnnotation("y2022")
    private Zoo zoo2022;
    

    【讨论】:

    • 谢谢,我不知道InjectionPoint。为了使您的示例正常工作,我必须将YearAnnotation 中的value 默认为某个值,否则@YearAnnotation 将不会在@Producer 方法中被接受。我还必须在Zoos 构造函数中删除@Inject
    • 我想知道这是否是最好的方法。想象一下,我还有一个Country,其中应该注入一个Zoo。以同样的方式,@YearAnnotation("...") 应指示将哪个Zoo 注入Country。按照您的解决方案,然后我将添加一个 @Produces @YearAnnotation Country makeCountry(InjectionPoint ip) 方法。在里面我会做类似return new Country(new Zoo(yearValue))的事情,不是吗?我想知道这是否很好,因为我会在这个方法中链接news。这不是我们想要通过依赖注入避免的事情吗?
    • 这种方法与我在刚刚发布的答案中提出的方法相比如何?按照那里所述的方法,我可以为makeCountry 添加两个类似的方法。恕我直言,好处是每个方法只有一个new;缺点是更多的方法。
    【解决方案2】:

    另一种解决方案是为Zoos 添加@Produces 方法。这些使用问题中已经说明的@Produces 方法给出的Year 实例。

    @Produces @YearAnnotation("y2021")
    public static Zoo makeZooYear2021(@YearAnnotation("y2021") Year year)
    {
        return new Zoo(year);
    }
    
    @Produces @YearAnnotation("y2022")
    public static Zoo makeZooYear2022(@YearAnnotation("y2022") Year year)
    {
        return new Zoo(year);
    } 
    

    要完成这项工作,必须删除 Zoo 构造函数中的 @Inject

    【讨论】:

    • 是否可以通过将这两个功能组合成一个功能来改善这一点?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多