我们可以将工厂类作为spring bean并且有一个工厂方法根据条件返回多个spring bean吗?

问题描述 投票:1回答:4

我想根据工厂类中的条件返回多个spring bean。

这是一个好习惯吗?

有没有更好的方法来编写以下代码?这里适合的任何其他设计模式?

以下是代码段:

package com.test;

import org.springframework.stereotype.Component;
import javax.annotation.Resource;


@Component
public class InstanceFactory {

    @Resource(name = "instance1")
    private Instance instance1;

    @Resource(name = "instance2")
    private Instance instance2;

    public Instance getService(Condition condition) {
        if (condition.one() && condition.two()) {
            return instance2;
        } else {
            return instance1;
        }
    }
}
java spring design-patterns factory
4个回答
0
投票

这取决于你想要达到的目标。工厂模式用于创建对象,但是您返回的是已经在其他地方创建的对象(在本例中为Spring)。如果你想创建由Spring管理的bean,有几种方法:

@Conditional(YourConditionImplementation.class):在@Configuration带注释的类的方法上添加的这个注释将允许您在给定条件完全填充时创建bean。示例:https://javapapers.com/spring/spring-conditional-annotation/

您也可以使用BeanFactory将bean的定义(DefinitionBean)注入容器中。示例:https://www.logicbig.com/tutorials/spring-framework/spring-core/bean-definition.html

现在,如果你想要一个确定Instance类型的对象更适合某些需求的对象,那么你的方法是可以的,但从技术上来说它不是工厂:)


0
投票

在设计类似的东西时,我会考虑两种设计模式来面对该解决方案:

  • 策略模式:为了在每次需要评估更多实例时替换重复if else。
  • 装饰器模式:尽量使每个条件都可配置。它们可以由一个或多个谓词组成(装饰)。

考虑到这两个模式你可能会实现这样的事情:

首先,定义哪些条件将标识给定实例:

public enum InstanceType {
    INSTANCE_TYPE_1(Condition::isOne, Condition::isTwo),
    INSTANCE_TYPE_2(Condition::isOne, Condition::isThree),
    ...;
    private List<Predicate<Condition>> evaluators;

    @SafeVarargs
    InstanceType(final Predicate<Condition>... evaluators) {
        this.evaluators = Arrays.asList(evaluators);
    }

    public boolean evaluate(final Condition condition) {
        return evaluators.stream().allMatch(it -> it.test(condition));
    }
}

然后,您应该将每个实例实现链接到特定的实例类型:

@Component
public class InstanceOne implements Instance {
    @Override
    public InstanceType getType() {
        return InstanceType.INSTANCE_TYPE_1;
    }
}

最后,配置一个类,将类型和实例之间的关系定义为EnumMap

@Configuration
public class InstanceFactoryConfig {
    @Autowired
    private List<Instance> instances;

    @Bean
    public EnumMap<InstanceType, Instance> instancesMap() {
        EnumMap<InstanceType, Instance> instanceEnumMap = new EnumMap<>(InstanceType.class);
        instances.forEach(i -> instanceEnumMap.put(i.getType(), i));
        return instanceEnumMap;
    }
}

因此,您可以将InstanceFactory替换为以下内容:

public class InstanceFactory {
    @Autowire
    private final EnumMap<InstanceType, Instance> instancesMap;

    public void getInstance(Condition condition) {
        instancesMap.get(getInstanceType(condition)).doSomething();
    }

    private InstanceType getInstanceType(Condition condition) {
        return Arrays.stream(InstancesType.values())
            .filter(evaluator -> evaluator.evaluate(condition))
            .findFirst().orElseThrow(() -> new RuntimeException("Instance type not found"));
    }
}

如您所见,InstanceFactory不太容易被修改。这意味着,每次需要添加新实例实现时,只需要修改InstanceType枚举。希望这是有帮助的。


0
投票

见:Spring Profile

活动配置文件由属性设置,并根据您为配置文件分配的值,Spring将为同一接口加载不同的bean。 所以它可能正是你所需要的。


0
投票

您可以使用spring现有的FactoryBean接口并实现您自己的逻辑它是在spring框架中创建bean的最佳方法之一以下是带有示例的链接:

https://www.baeldung.com/spring-factorybean

© www.soinside.com 2019 - 2024. All rights reserved.