0

我正在设计一个视频文件转换引擎。

有不同的来源(带有开始/结束时间码的文件、播放列表文件、描述输入文件的各种文本/XML 文件以及应用于这些文件的视频/音频效果,...)。

有不同的输出(文件或命令文本文件)。

可以运行不同的工具(主要是 dos 命令)来进行转换。

我想设计一个遵循开放/封闭原则的引擎,以轻松添加/修改新源或新输出。

我想避免有太多的类,所以我认为继承不是一个选择。

我想过创建一个中心类转换器。

引擎将从源创建此 Converter 类并将源转换为输出。

我不知道这是否是一个好方法。

我查看了策略模式,但同样,我不确定这是使用合适的模式。

4

3 回答 3

2

我看到了两种主要的方法来解决这个问题,都基于策略模式:

  1. 为输入和输出的每个排列创建一个类,该类将在所述输入和输出之间进行转换,然后将它们放入具有中央转换器类的策略模式中,该类可以从它找到或给出的实现集合中选择正确的实现。

    • 好处是简单,每个现有的实现一旦工作,都应该“关闭”以根据添加额外的输入或输出类型进行更改。
    • 缺点是对于 5 个输入和 2 个输出,您需要 10 个实现。添加第三个输出需要再开发 5 个类,每个输入一个。你也可能会经常重复自己;考虑让所有这些类都派生自一个抽象基础,您可以使用它来将公共代码“拉起”到一个地方。
  2. 为每个输入创建一个类,该类可以将该特定输入转换为某种中间的内存格式,其中包含生成任何输出所需的所有信息。然后,为每个输出创建一个类,该类将在给定任何给定输入转换产生的中间值的情况下产生所述输出。将所有这些放入一个中央转换器中,该转换器将根据特定情况的需要“混合和匹配”输入和输出转换。

    • 好处是添加新的输出类型不需要您创建与输入类型一样多的实现,反之亦然。您的重复代码也更少;有一种方法可以将任何给定的输入转换为中间体,还有一种方法可以将中间体转换为给定的输出,因此您不应该发现自己在两个不同的实现中进行相同的方法调用(尽管实现仍然可以从抽象派生基础以允许共享代码)。
    • 缺点是内部复杂性增加,对变化更敏感。中介类型是必需的,尽管您的代码之外的任何东西都不会使用它,并且如果需要存储在中介中的信息量发生变化(比如支持需要比您当前从输入中提供的更多信息的新输出) ),您将需要返回并更改现有的工作代码以添加另一端所需的新数据。

哪一个更适合你,取决于你预测这个系统必须经历什么样的变化。如果您预见到要添加新类型的输入或输出,中介将是更好的模式,因为它减少了类数(5 个输入,3 个输出是 8 个转换器而不是 15 个);但是,您需要确保中介也遵循开放/封闭原则,因此可以添加必须提供或使用新数据的输入或输出的新实现,并扩展中介,而不会彻底破坏现有实现或确保输入和输出的组合不兼容。如果您预见到数据的类型或数量,您需要改变的不仅仅是获取或输出它的方式,或者如果您预见到每个输入和输出之间的转换过程会有如此巨大的不同,那么

于 2012-04-10T16:23:18.333 回答
1

根据皮埃尔的评论更新:

定义一个通用转换器如下:

public interface IVideoConverter
{
     IInputReader  Reader {get;set;}
     IOutputWriter Writer {get;set;}
     void Convert();
}

定义接口:

public interface IInputReader
{
    bool IsSUpported(string inputId);

    void AppendToBuffer(Buffer buffer);
}

public interface IOutputWriter
{
    bool IsSUpported(string outputId);

    void WriteFromBuffer(Buffer buffer);
}

编写实现转换器的类:

public class VideoConverter : IVideoConverter
{
   ...       
}

写3个工厂:

public class InputReaderFactory
{
   public IInputReader GetReader(string inputId)
   {
       ...
   }
}

public class OutputWriterFactory
{
   public IOutputWriter GetWriter(string outputId)
   {
      ...
   }
}

public class VideoConverterFactory
{
   public IVideoConverter GetConverter(string inputId, string outputId)
   {
      ...
   } 
}

在每个工厂中,使用您想要构建工厂负责的实例的任何方法。VideoConverterFactory 应该使用读取器和写入器工厂

有几种方法可以实现具体的类型初始化。我将描述2:

a) 创建一个静态只读数组或所有受支持类型的列表,并在此列表中搜索支持给定输入参数的第一个转换器。

 public class InputReaderFactory
 {
   private static readonly IEnumerable<IInputReader> SupportedReaders = new IInputReader[] {new Reader1(), new Reader2(),....}
   public IInputReader GetReader(string inputId)
   {
      for(int i=0; i<SupportedReaders .length; i++)
      {
        if(SupportedReaders [i].IsSupported(inputId)
          return SupportedReaders [i];
      }

      return null;
   }
}

b)在配置文件中定义支持的类型(实现配置元素,配置集合和部分),并在工厂类中从配置中搜索支持的转换器,当找到一个时,使用反射创建一个实例

于 2012-04-10T16:34:20.447 回答
1

您可能需要模式组合以及非模式代码的一些实际应用。策略模式非常适合填写“我如何加载/编写这个?”。复合图案适用于“将这些元素缝合在一起”或“做这种过渡效果”。装饰器模式非常适合在视频之上应用效果。

症结在于提供一个通用接口,您可以以有意义的方式实现和装饰。如果不知道更多关于您希望实施的行为,很难说。

于 2012-04-10T16:19:04.357 回答