这是策略模式的一个很好的用例吗?

时间:2012-04-16 02:20:55

标签: php design-patterns language-agnostic factory-pattern strategy-pattern

我正在使用需要接收多个视频的应用程序,并将其显示在特定页面上,目前这些视频只能来自YouTube,因为实施不允许其他提供商,因为要获取的代码视频数据作为预览图像直接放置在负责显示视频的View Helper中。

我想更改此结构以便于添加新的提供程序(例如Vimeo),我认为策略模式将是理想的,我将在View Helper中使用方法setVideoUrl( string $url ),此方法将从getProviderStrategy( string $url )调用方法class VideoProviderFactory,此工厂类将返回(如果可用的话)为视频网址提供者实现interface VideoProvider的策略类。

你怎么看?这是对的?我需要改变什么吗?

详细信息:我最初考虑过直接在View Helper中选择策略,但在阅读完这个问题之后:Strategy Pattern with no 'switch' statements?我看到我错了,class VideoProviderFactory出现了

1 个答案:

答案 0 :(得分:5)

这看起来是一个非常好的设计,适当分离责任。

为了给您提供更多的思考,请考虑 工厂将决定创建哪种策略。稍后当您想要添加另一个策略时,需要更改哪些内容?首先,您需要创建一个新的VideoProvider,然后您必须更改工厂switch语句(如您所述)并包含此新策略的选择逻辑。现在,这在大多数情况下都非常好,但是如果你想在不改变工厂的情况下添加新策略呢?

一种方法是使用类似工厂的界面,该方法根据URL决定是否应该创建特定的VideoProvider;我们称之为VideoProviderMatcher(伪代码):

interface VideoProviderMatcher {
  bool understands(url)
  VideoProvider create()
}

现在,此界面知道它是否了解URL以及如何创建与其相关的VideoProvider。当您需要创建新策略时,您需要同时实施VideoProvider和相关的VideoProviderMatcher。对于工厂,它更改为使用责任链(伪代码)将VideoProviderMatcher和委托的列表封装到第一个理解给定URL的列表:

class VideoProviderFactory {
  List[VideoProviderMatcher] matchers
  void registerMatcher(VideoProviderMatcher matcher) {
    matchers.add(matcher)
  }
  VideoProvider getVideoProviderFor(url) {
    foreach (matcher in matchers) {
      if (matcher.understands(url)) return matcher.create()
    }
  }
}

现在唯一需要更改的代码是首先创建工厂的代码。理想情况下,它有一个用于填充工厂的VideoProviderMatcher列表,您只需将另一个项目添加到列表中。

现在,这值得吗?我要说这取决于匹配逻辑的复杂性,将URL匹配与视频提供者一起封装的意愿,在添加新策略时保持工厂稳定的愿望,以及添加新策略的速度解决方案。