Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Strategy pattern with spring beans

Say I'm using spring, I have the following strategies...

Interface

public interface MealStrategy {     cook(Meat meat); } 

First strategy

@Component public class BurgerStrategy  implements MealStrategy {   @Autowired CookerDao cookeryDao;    @Override   public void cook(Meat meat) {       cookeryDao.getBurger(meat);   } } 

Next strategy...

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

Now say this context was being accessed through an mvc controller, like...

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

Should the context be a component? When I do I get an error saying loadOnStartup an there's a nonUniqueBean that the strategy could be, as you'd expect. Do all of the beans need to be components like above or are my annotations incorrect?

My biggest query really is can you use a context like that in a Spring MVC app? The problem I have with using @Scope(prototype) too is it means the cookeryDao calls in the strategies return a null pointer as the Dao's don't get injected.

How would I implement the above pattern using spring and also be thread safe? Is what I'm trying even possible?

like image 663
david99world Avatar asked Jul 13 '13 11:07

david99world


People also ask

Does Spring Use strategy pattern?

There is a lot of debate around the use of the Strategy Pattern with Spring. Often you'll see the Strategy Pattern used in conjunction with Dependency Injection, where Springs IoC container is making the choice of which strategy to use.

What are strategies in Spring?

The Strategy Pattern is a behavioral design pattern that enables selecting an algorithm at runtime. I'll explain in this tutorial one way to implement it using the spring framework and leveraging its dependency injection power.


2 Answers

Since a concrete strategy is very often determined at run time based on the provided parameters or so, I would suggest something as follows.

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

Then inject all such strategies into a map (with bean name as a key) in the given controller and select respective strategy on request.

@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);      ... } 
like image 113
pgiecek Avatar answered Sep 28 '22 18:09

pgiecek


I would use simple Dependency Injection.

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

Controller

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

You can choose to create JSR-330 qualifiers instead of textual names to catch misspellings during compile time.

See also:

How to efficiently implement a strategy pattern with spring?

@Resource vs @Autowired

like image 37
anttix Avatar answered Sep 28 '22 18:09

anttix