视频文件转换引擎的OOP设计

本文关键字:OOP 设计 引擎 文件 转换 视频 | 更新日期: 2023-09-27 18:30:49

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

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

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

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

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

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

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

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

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

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

视频文件转换引擎的OOP设计

我看到了两种主要的方法,都基于策略模式:

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

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

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

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

您可能需要模式

的组合以及非模式代码的一些实际应用。策略模式非常适合填写"我如何加载/编写这个?复合图案适用于"将这些元素缝合在一起"或"执行此过渡效果"。装饰器模式适用于在视频顶部应用效果。

症结在于提供一个通用接口,您可以以有意义的方式实现和装饰该接口。如果不了解您要实施的行为,就很难说。

根据皮埃尔的评论进行更新:

定义通用转换器,如下所示:

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