Domanda Modello di strategia con fagioli primavera


Diciamo che sto usando la primavera, ho le seguenti strategie ...

Interfaccia

public interface MealStrategy {
    cook(Meat meat);
}

Prima strategia

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

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

Prossima strategia ...

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

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

Contesto...

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

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

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

Ora diciamo che questo contesto era accessibile tramite un controller mvc, come ...

@Autowired
private MealContext mealContext;

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

Il contesto dovrebbe essere un componente? Quando ottengo un errore che dice loadOnStartup c'è un nonUniqueBean che la strategia potrebbe essere, come ci si aspetterebbe. Tutti i bean devono essere componenti come sopra o le mie annotazioni sono errate?

La mia più grande domanda è in realtà è possibile utilizzare un contesto come quello in un'app di Spring MVC? Il problema che ho con l'uso di @Scope (prototipo) è che le chiamate di cookery nelle strategie restituiscono un puntatore nullo poiché i Dao non vengono iniettati.

Come potrei implementare il modello sopra usando la molla e anche essere thread-safe? E 'quello che sto provando anche possibile?


13
2017-07-13 11:30


origine


risposte:


Io userei la semplice Iniezione delle Dipendenze.

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

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

controllore

Opzione A:

@Resource(name = "burger")
MealStrategy burger;

@Resource(name = "sausage")
MealStrategy sausage;

@RequestMapping(method = RequestMethod.POST)
public @ResponseBody Something makeMeal(Meat meat) {
    burger.cookMeal(meat);
}

Opzione B:

@Autowired
BeanFactory bf;

@RequestMapping(method = RequestMethod.POST)
public @ResponseBody Something makeMeal(Meat meat) {
    bf.getBean("burger", MealStrategy.class).cookMeal(meat);
}

Puoi scegliere di creare qualificatori JSR-330 invece di nomi testuali per catturare errori ortografici durante la compilazione.

Guarda anche:

Come implementare in modo efficiente un modello di strategia con la primavera?

@Resource vs @Autowired


19
2017-07-13 12:23



Dal momento che una strategia concreta è molto spesso determinata in fase di esecuzione sulla base dei parametri forniti o così, vorrei suggerire qualcosa come segue.

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

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

Quindi iniettare tutte queste strategie in una mappa (con nome bean come chiave) nel controller specificato e selezionare la rispettiva strategia su richiesta.

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

    ...
}

27
2017-11-24 20:46