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


Is this a good use case of the Strategy Pattern?

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

我想更改此结构以轻松添加新提供程序,例如Vimeo,我认为策略模式将是理想的,我将在我的视图助手中setVideoUrl( string $url )方法,此方法将从class VideoProviderFactory调用方法getProviderStrategy( string $url ),然后该工厂类将返回, 如果可用,则为视频 URL 的提供程序实现interface VideoProvider的策略类。

你觉得怎么样?这是对的吗?我需要改变一些东西吗?

细节:我最初考虑将一个开关直接放入视图助手中以选择策略,但在阅读了这个问题之后:I 没有"开关"语句的策略模式?我看到我错了,然后class VideoProviderFactory出现了。

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

为了给您更多的思考,请考虑工厂将如何决定创建哪种策略。稍后当您想要添加另一个策略时,需要更改什么?首先,您将创建一个新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 匹配与视频提供商封装在一起的意愿、添加新策略时保持工厂稳定的愿望,以及将新策略添加到解决方案中的速率。