Стратегия с spring beans
Скажем, что я использую spring, у меня есть следующие стратегии...
Интерфейс
public interface MealStrategy {
cook(Meat meat);
}
Первая стратегия
@Component
public class BurgerStrategy implements
MealStrategy {
@Autowired CookerDao cookeryDao;
@Override
public void cook(Meat meat) {
cookeryDao.getBurger(meat);
}
}
Следующая стратегия...
@Component
public class SausageStrategy implements
MealStrategy {
@Autowired CookerDao cookeryDao;
@Override
public cook(Meat meat) {
return cookeryDao.getSausage(meat);
}
}
Context...
@Component
@Scope("prototype")
public class MealContext {
private MealStrategy mealStrategy;
public void setMealStrategy(MealStrategy strategy) {
this.strategy = strategy;
}
public void cookMeal(Meat meat) {
mealStrategy.cook;
}
}
Теперь скажем, что этот контекст был доступен через контроллер mvc, например...
@Autowired
private MealContext mealContext;
@RequestMapping(method = RequestMethod.POST)
public @ResponseBody Something makeMeal(Meat meat) {
mealContext.setMealStrategy(new BurgerStrategy())
mealContext.cookMeal(meat);
}
Должен ли контекст быть компонентом? Когда я это сделаю, я получаю сообщение об ошибке loadOnStartup, где есть unUniqueBean, что стратегия может быть, как и следовало ожидать. Должны ли все beans быть такими компонентами, как указано выше, или мои аннотации неверны?
В самом деле, мой самый большой запрос - вы можете использовать такой контекст в приложении Spring MVC? Проблема, с которой я сталкиваюсь с использованием @Scope (прототип), также означает, что вызовы cookeryDao в стратегиях возвращают нулевой указатель, поскольку Дао не вводится.
Как реализовать описанный выше шаблон с помощью Spring, а также быть потокобезопасным? Является ли то, что я пытаюсь даже сделать возможным?
Ответы
Ответ 1
Я бы использовал простую инъекцию зависимостей.
@Component("burger")
public class BurgerStrategy implements MealStrategy { ... }
@Component("sausage")
public class SausageStrategy implements MealStrategy { ... }
контроллер
Вариант A:
@Resource(name = "burger")
MealStrategy burger;
@Resource(name = "sausage")
MealStrategy sausage;
@RequestMapping(method = RequestMethod.POST)
public @ResponseBody Something makeMeal(Meat meat) {
burger.cookMeal(meat);
}
Вариант B:
@Autowired
BeanFactory bf;
@RequestMapping(method = RequestMethod.POST)
public @ResponseBody Something makeMeal(Meat meat) {
bf.getBean("burger", MealStrategy.class).cookMeal(meat);
}
Вы можете создавать квалификаторы JSR-330 вместо текстовых имен для обнаружения орфографических ошибок во время компиляции.
См. также:
Как эффективно реализовать шаблон стратегии с помощью spring?
@Resource vs @Autowired
Ответ 2
Поскольку конкретная стратегия очень часто определяется во время выполнения на основе предоставленных параметров или около того, я бы предложил что-то следующее.
@Component
public class BurgerStrategy implements MealStrategy { ... }
@Component
public class SausageStrategy implements MealStrategy { ... }
Затем внедрите все такие стратегии в карту (с именем bean в качестве ключа) в данном контроллере и выберите соответствующую стратегию по запросу.
@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);
...
}