2
votes

Pouvons-nous avoir une classe d'usine comme haricot de printemps et avoir une méthode d'usine renvoyant plusieurs haricots de printemps en fonction de la condition?

Je souhaite renvoyer plusieurs beans spring en fonction de la condition de la classe factory.

Est-ce une bonne pratique?

Y a-t-il de meilleures façons d'écrire le morceau de code suivant ?. Y a-t-il d'autres modèles de conception appropriés ici?

Voici l'extrait de code:

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 commentaires

Cela me semble parfaitement bien. Bien que cela dépende probablement de votre état de santé.


Cela ressemble à une question pour codereview.stackexchange.com


connaissez-vous FactoryBeans? ou selon la condition, les profils peuvent être utiles. pour qu'il y ait une réponse claire, il devrait y avoir plus de détails.


Merci @biziclop et Nathan Hughes. Je vais examiner les FactoryBeans


4 Réponses :


0
votes

Cela dépend de ce que vous voulez réaliser. Factory Pattern est destiné à créer des objets, mais ce que vous renvoyez sont des objets déjà créés ailleurs (Spring dans ce cas). Si vous souhaitez créer des beans qui seront gérés par Spring, il existe plusieurs façons:

@Conditional (YourConditionImplementation.class): Cette annotation ajoutée sur une méthode d'une classe annotée @Configuration vous permettra de créer un bean lorsque la condition donnée est remplie. Exemple ici: https://javapapers.com/spring/spring-conditional-annotation/

Vous pouvez également utiliser BeanFactory pour injecter la définition de votre bean (DefinitionBean) dans le conteneur. Exemple ici: https://www.logicbig.com /tutorials/spring-framework/spring-core/bean-definition.html

Maintenant, si vous voulez un objet qui détermine quel objet de type Instance correspond le mieux à certains besoins, votre approche est correcte, mais ce n'est pas techniquement une usine :)


2 commentaires

Il n'est pas recommandé d'utiliser @ConditionOnMissingBean pas dans la bibliothèque de configuration automatique de démarrage de printemps, etc.


Il est recommandé selon la documentation du printemps: docs.spring.io/spring-boot/docs/current/reference/html/… . De toute façon, personne n'a rien dit sur les bottes à ressort. Pour le moment, ce n'est que spring et @conditional avec une classe de condition personnalisée.



0
votes

Lors de la conception de quelque chose comme ça, je ferais face à cette solution en considérant deux modèles de conception:

  • Modèle de stratégie: pour remplacer les répétitions if else chaque fois que vous devez évaluer plus d'instances.
  • Modèle de décorateur: essayer de rendre chaque condition aussi configurable que possible. Ils peuvent être composés (décorés) pour un ou plusieurs prédicats.

En considérant ces deux modèles, vous pourriez réaliser quelque chose comme ceci:

Tout d'abord, définissez quelles conditions identifieront une instance donnée:

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

Ensuite, vous devez lier chaque implémentation d'instance à un type d'instance spécifique:

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

Enfin, une classe à configurer où définissant la relation entre les types et les instances comme EnumMap

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

Ainsi, votre InstanceFactory peut être remplacée par quelque chose comme ceci:

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

Comme vous pouvez le voir, votre InstanceFactory est moins encline à être modifié. Cela signifie qu'à chaque fois que vous avez besoin d'ajouter une nouvelle implémentation d'instance, il vous suffit de modifier l'énumération InstanceType. J'espère que cela aide.


0 commentaires

-1
votes

Voir: Spring Profile

Le profil actif est défini par les propriétés et en fonction de la valeur que vous attribuez au profil, Spring chargera différents beans pour la même interface.
C'est peut-être exactement ce dont vous avez besoin.


0 commentaires

0
votes

Vous pouvez utiliser l'interface FactoryBean existante et implémenter votre propre logique C’est l’une des meilleures approches pour créer des beans dans Spring Framework Voici le lien avec l'exemple:

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


0 commentaires