2013-07-13 13 views
12

Sagen wir, ich bin mit Frühling, ich habe die folgenden Strategien ...Strategie Muster mit Frühlings Bohnen

Schnittstelle

public interface MealStrategy { 
    cook(Meat meat); 
} 

Erste Strategie

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

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

Nächste Strategie ...

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

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

Cont ext ...

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

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

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

Nun sagen dieser Zusammenhang durch einen Mvc-Controller zugegriffen wurde, wie ...

@Autowired 
private MealContext mealContext; 

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

Sollte der Kontext eine Komponente sein? Wenn ich das tue, bekomme ich einen Fehler, der loadOnStartup sagt und es gibt eine nonUniqueBean, die die Strategie sein könnte, wie Sie es erwarten würden. Müssen alle Beans Komponenten wie oben sein oder sind meine Anmerkungen falsch?

Meine größte Abfrage ist wirklich, können Sie einen Kontext wie diesen in einer Spring MVC App verwenden? Das Problem, das ich bei der Verwendung von @Scope (Prototyp) habe, ist auch, dass die cookeryDao-Aufrufe in den Strategien einen Nullzeiger zurückgeben, da die Daos nicht injiziert werden.

Wie würde ich das obige Muster mit Feder implementieren und auch threadsicher sein? Ist das, was ich versuche, sogar möglich?

+0

Was ist genau dein Problem? all das funktioniert für mich – morgano

+0

Ich möchte wissen, ob es Thread sicher ist, einen Kontext zu haben, wie ich – david99world

+0

getan habe, auch das obige würde nicht funktionieren, weil, wie ich 'neue' gemacht habe, dies außerhalb des Frühlingszusammenhangs ist? – david99world

Antwort

16

Ich würde einfache Dependency Injection verwenden.

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

Sie können wählen, JSR-330-Qualifikation statt Textnamen erstellen Fehlbuchstabierungen während der Kompilierung zu fangen Zeit. auch

Siehe:

How to efficiently implement a strategy pattern with spring?

@Resource vs @Autowired

20

Da eine konkrete Strategie sehr häufig zur Laufzeit auf der Basis der vorgegebenen Parameter oder so bestimmt wird, würde ich etwas vorschlagen, wie folgt.

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

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

Dann alle diese Strategien in eine Karte injizieren (mit Bohnen Namen als Schlüssel) in dem angegebenen Controller und wählen Sie entsprechende Strategie auf Anfrage.

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

    ... 
} 
+1

Diese Antwort gibt eine genauere Implementierung des Strategie-Patterns – Cuga