Статьи

Стратегия не предназначена для весны!

Итак, предположим, что вы пишете приложение Spring MVC и решаете: «Я хочу создать отдельные инкапсулированные алгоритмы, которые можно поменять местами для выполнения определенного поведения».

Классическим ответом на это было бы «вам нужен шаблон стратегии, мама!». Итак, вот что я сделал, рассмотрим код ниже …

Интерфейс

1
2
3
public interface MealStrategy {
    cook(Meat meat);
}

Первая стратегия

01
02
03
04
05
06
07
08
09
10
@Component
public class BurgerStrategy  implements
MealStrategy {
  @Autowired CookerDao cookeryDao;
 
  @Override
  public void cook(Meat meat) {
      cookeryDao.getBurger(meat);
  }
}

Следующая стратегия …

01
02
03
04
05
06
07
08
09
10
@Component
public class SausageStrategy  implements
MealStrategy {
  @Autowired CookerDao cookeryDao;
 
  @Override
  public cook(Meat meat) {
      return cookeryDao.getSausage(meat);
  }
}

Контекст …

01
02
03
04
05
06
07
08
09
10
11
12
13
@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, например …

1
2
3
4
5
6
7
8
@Autowired
private MealContext mealContext;
 
@RequestMapping(method = RequestMethod.POST)
public @ResponseBody Something makeMeal(Meat meat) {
    mealContext.setMealStrategy(new BurgerStrategy());
    mealContext.cookMeal(meat);
}

Обычно это имеет смысл для использования с шаблоном стратегии. Тем не менее, единственная строка, которая заставляет все это рухнуть, это строка в контроллере …

1
mealContext.setMealStrategy(new BurgerStrategy())

Это приведет к тому, что новый экземпляр компонента будет создан вне контекста приложения Spring. Это любопытно, так как вам следует реализовать шаблон в Spring, если вы не можете использовать new для создания нового экземпляра? Задав этот вопрос в StackOverflow, я пришел к выводу, что нужно использовать шаблон внедрения зависимостей (в соответствии со стандартным автоматическим подключением весной) и делать отдельные инъекции стратегий. Во-первых, мне нужно изменить стратегии, чтобы они называли компоненты.

1
2
3
4
5
@Component("burger")
public class BurgerStrategy implements MealStrategy { ... }
 
@Component("sausage")
public class SausageStrategy implements SausageStrategy { ... }

Теперь в контроллере у меня есть отдельные стратегии для использования, поэтому вместо того, чтобы устанавливать стратегию, я просто выбираю соответствующую, которая вводится.

01
02
03
04
05
06
07
08
09
10
@Resource(name = "burger")
MealStrategy burger;
 
@Resource(name = "sausage")
MealStrategy sausage;
 
@RequestMapping(method = RequestMethod.POST)
public @ResponseBody Something makeMeal(Meat meat) {
    burger.cookMeal(meat);
}

Справка: шаблон стратегии не предназначен для весны! от нашего партнера JCG Дэвида Грея в блоге Code Mumble .