Стратегия с 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);

    ...
}