Можем ли мы иметь фабричный класс в виде пружинного компонента и иметь метод фабрики, возвращающий несколько пружинных компонентов в зависимости от условия? - PullRequest
1 голос
/ 11 апреля 2019

Я хочу вернуть несколько пружинных бобов в зависимости от условия в фабричном классе.

Это хорошая практика?

Есть ли лучшие способы написать следующий фрагмент кода? Любые другие шаблоны дизайна, подходящие здесь?

Ниже приведен фрагмент кода:

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;
        }
    }
}

Ответы [ 4 ]

0 голосов
/ 15 апреля 2019

Вы можете использовать существующий SpringBean-интерфейс и реализовать собственную логику. Это один из лучших подходов для создания бобов в среде Spring. Вот ссылка с примером:

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

0 голосов
/ 14 апреля 2019

При проектировании чего-то подобного я столкнулся бы с этим решением с учетом двух шаблонов проектирования:

  • Шаблон стратегии: для замены повторяющегося , если еще каждый раз, когда вам нужно оценить большеinstances.
  • Шаблон декоратора: Попытка сделать каждое условие максимально настраиваемым.Они могут быть составлены (декорированы) для одного или нескольких предикатов.

С учетом этих двух шаблонов вы можете достичь чего-то подобного:

Сначала определите, какие условия будут идентифицировать данный экземпляр:

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 голосов
/ 15 апреля 2019

См: пружинный профиль

Активный профиль задается свойствами и в зависимости от значения, которое вы назначаете профилю, Spring будет загружать разные bean-компоненты для одного и того же интерфейса.
Так что это может быть именно то, что вам нужно.

0 голосов
/ 11 апреля 2019

Это зависит от того, чего вы хотите достичь. Factory Pattern предназначен для создания объектов, но вы возвращаете объекты, уже созданные где-то еще (в данном случае Spring). Если вы хотите создать bean-компоненты, которыми будет управлять Spring, есть несколько способов:

@ Conditional (YourConditionImplementation.class): эта аннотация, добавленная к методу аннотированного класса @Configuration, позволит вам создать компонент, когда данное условие будет выполнено. Пример здесь: https://javapapers.com/spring/spring-conditional-annotation/

Вы также можете использовать BeanFactory для добавления определения вашего компонента (DefinitionBean) в контейнер. Пример здесь: https://www.logicbig.com/tutorials/spring-framework/spring-core/bean-definition.html

Теперь, если вам нужен объект, который определяет, какой объект типа Instance лучше подходит для некоторых нужд, тогда ваш подход в порядке, но технически это не фабрика:)

...