【问题标题】:Strategy pattern with spring beans春豆战略模式
【发布时间】:2013-07-11 20:56:29
【问题描述】:

说我在用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);
  }
}

上下文...

@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 并且正如您所期望的那样,该策略可能是一个 nonUniqueBean。是不是所有的 bean 都需要像上面这样的组件,还是我的注释不正确?

我最大的疑问是你能在 Spring MVC 应用程序中使用这样的上下文吗?我使用@Scope(prototype) 的问题也是这意味着策略中的cookeryDao 调用返回一个空指针,因为Dao 没有被注入。

如何使用 spring 实现上述模式并且线程安全?我正在尝试的可能吗?

【问题讨论】:

  • 您的问题到底是什么?这一切都对我有用
  • 我想知道像我这样拥有上下文是否是线程安全的
  • 以上也行不通,因为正如我所做的那样new 这不在 Spring 上下文中?

标签: java spring strategy-pattern


【解决方案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 限定符而不是文本名称,以便在编译期间发现拼写错误。

另见:

How to efficiently implement a strategy pattern with spring?

@Resource vs @Autowired

【讨论】:

  • 选项 1 真的是一个解决方案吗?每次我们需要将实现类自动装配为资源时。让我们说我们最终拥有 100 个......控制器类不会太难管理吗?
【解决方案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);

    ...
}

【讨论】:

  • 这个答案给出了策略模式的更真实的实现
  • 组件不是默认单例吗?
  • 我知道这是一篇旧帖子,但“mealStrategyId”的格式是什么,是类名还是完全限定名?
  • 是的就是 bean 名称
  • 好的策略模式示例。点赞。 Nitpick,您很可能只需要“Map mealStrategies;”而不是新的,因为集合是注入的。如果你有多个构造函数,也许你会保留新的。但这很少见。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多