web-dev-qa-db-fra.com

Modèle de stratégie avec des haricots de printemps

Disons que j'utilise le printemps, j'ai les stratégies suivantes ...

Interface

public interface MealStrategy {
    cook(Meat meat);
}

Première stratégie

@Component
public class BurgerStrategy  implements
MealStrategy {
  @Autowired CookerDao cookeryDao;

  @Override
  public void cook(Meat meat) {
      cookeryDao.getBurger(meat);
  }
}

Prochaine stratégie ...

@Component
public class SausageStrategy  implements
MealStrategy {
  @Autowired CookerDao cookeryDao;

  @Override
  public cook(Meat meat) {
      return cookeryDao.getSausage(meat);
  }
}

Le contexte...

@Component
@Scope("prototype")
public class MealContext {
    private MealStrategy mealStrategy;

    public void setMealStrategy(MealStrategy strategy) {
        this.strategy = strategy;
    }

    public void cookMeal(Meat meat) {
        mealStrategy.cook;
    }
}

Maintenant, disons que ce contexte était accessible via un contrôleur mvc, comme ...

@Autowired
private MealContext mealContext;

@RequestMapping(method = RequestMethod.POST)
public @ResponseBody Something makeMeal(Meat meat) {
    mealContext.setMealStrategy(new BurgerStrategy())
    mealContext.cookMeal(meat);
}

Le contexte devrait-il être un composant? Quand je le fais, j'obtiens une erreur disant loadOnStartup et il y a un nonUniqueBean que la stratégie pourrait être, comme vous vous en doutez. Tous les beans doivent-ils être des composants comme ci-dessus ou mes annotations sont-elles incorrectes?

Ma plus grande requête est vraiment: pouvez-vous utiliser un contexte comme celui-ci dans une application Spring MVC? Le problème que j'ai avec l'utilisation de @Scope (prototype) est aussi que cela signifie que les appels cookeryDao dans les stratégies retournent un pointeur nul car les Dao ne sont pas injectés.

Comment pourrais-je implémenter le modèle ci-dessus en utilisant un ressort et être également sûr pour les threads? Est-ce que j'essaie même possible?

24
david99world

J'utiliserais une injection de dépendance simple.

@Component("burger")
public class BurgerStrategy implements MealStrategy { ... }

@Component("sausage")
public class SausageStrategy implements MealStrategy { ... }

Manette

Option A:

@Resource(name = "burger")
MealStrategy burger;

@Resource(name = "sausage")
MealStrategy sausage;

@RequestMapping(method = RequestMethod.POST)
public @ResponseBody Something makeMeal(Meat meat) {
    burger.cookMeal(meat);
}

Option B:

@Autowired
BeanFactory bf;

@RequestMapping(method = RequestMethod.POST)
public @ResponseBody Something makeMeal(Meat meat) {
    bf.getBean("burger", MealStrategy.class).cookMeal(meat);
}

Vous pouvez choisir de créer des qualificatifs JSR-330 au lieu de noms textuels pour intercepter les fautes d'orthographe pendant la compilation.

Voir également:

Comment mettre en œuvre efficacement un modèle de stratégie avec le printemps?

@ Ressource vs @Autowired

31
anttix

Puisqu'une stratégie concrète est très souvent déterminée au moment de l'exécution en fonction des paramètres fournis, je suggère quelque chose comme suit.

@Component
public class BurgerStrategy implements MealStrategy { ... }

@Component
public class SausageStrategy implements MealStrategy { ... }

Ensuite, injectez toutes ces stratégies dans une carte (avec le nom du bean comme clé) dans le contrôleur donné et sélectionnez la stratégie respective sur demande.

@Autowired
Map<String, MealStrategy> mealStrategies = new HashMap<>;

@RequestMapping(method=RequestMethod.POST)
public @ResponseBody Something makeMeal(@RequestParam(value="mealStrategyId") String mealStrategyId, Meat meat) {
    mealStrategies.get(mealStrategyId).cook(meat);

    ...
}
64
pgiecek