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