系统的类设计是分层的,但不是整齐的

Cha*_*rns 5 c# design-patterns .net-4.0

我已经多次遇到过这种情况,所以想用一个真实的例子来了解更有经验的C#开发人员如何处理这个问题.

我正在围绕非托管MediaInfo库编写一个.NET包装器,它收集有关媒体文件(电影,图像......)的各种数据.

MediaInfo有许多功能,每个功能适用于不同类型的文件.例如,"PixelAspectRatio"适用于图像和视频,但不适用于音频,字幕或其他内容.

我想要包装的功能的子集如下:

General Video   Audio    Text   Image  Chapters  Menu    (Name of function)    
x       x       x        x      x      x         x       Format
x       x       x        x      x      x         x       Title
x       x       x        x      x      x         x       UniqueID
x       x       x        x      x                x       CodecID
x       x       x        x      x                x       CodecID/Hint
        x       x        x      x                x       Language
x       x       x        x      x                        Encoded_Date
x       x       x        x      x                        Encoded_Library
x       x       x        x      x                        InternetMediaType
x       x       x        x      x                        StreamSize
        x       x        x      x                        BitDepth
        x       x        x      x                        Compression_Mode
        x       x        x      x                        Compression_Ratio
x       x       x        x                       x       Delay
x       x       x        x                       x       Duration
        x       x        x                               BitRate
        x       x        x                               BitRate_Mode
        x       x        x                               ChannelLayout
        x       x        x                               FrameCount
        x       x        x                               FrameRate
        x       x        x                               MuxingMode
        x       x        x                               MuxingMode
        x       x        x                               Source_Duration
        x                x      x                        Height
        x                x      x                        Width
        x                       x                        PixelAspectRatio
                x                                        SamplingRate
x                                                        Album
x                                                        AudioCount
x                                                        ChaptersCount
x                                                        EncodedBy
x                                                        Grouping
x                                                        ImageCount
x                                                        OverallBitRate
x                                                        OverallBitRate_Maximum
x                                                        OverallBitRate_Minimum
x                                                        OverallBitRate_Nominal
x                                                        TextCount
x                                                        VideoCount
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,一个非常糟糕的类映射的开始将是一个类,用于特定于每个流类型的功能,以及一个具有所有类型通用功能的基类.

然后这条道路变得不那么明显了.{general,video,audio,text和image}流类型有许多共同的功能.好吧,所以我想我可以创建一个像"GeneralVideoAudioTextImage"这样的臭名字的类,然后另一个名为GeneralVideoAudioText(继承自GeneralVideoAudioTextImage)的类,用于这些事物的共同功能,但不是"图像"流.我想这会尴尬地遵循"等级"的阶级等级规则.

这已经不是很优雅了,但是有一些偶然的情况,比如"Width",它们不适合任何一个干净地成为另一个组子集的组.这些案例可以在必要时简单地复制功能 - 分别在视频,文本和图像中实现,但这显然会违反DRY.

常见的第一种方法是MI,C#不支持.通常的答案似乎是"使用带接口的MI",但我无法完全看到它如何跟随DRY.也许是我失败了.

之前已经讨论过类层次结构,因为有MI的替代方法(扩展方法等),但这些解决方案似乎都不合适.例如,扩展方法似乎更适合用于无法编辑源的类,比如String类,并且更难定位,因为它们并不真正与类绑定,尽管它们可能有效.我没有找到关于这种情况的问题,尽管这可能是我使用搜索工具的失败.

包装的MediaInfo功能的示例可能是:

int _width = int.MinValue;
/// <summary>Width in pixels.</summary>
public int width {
    get {
        if(_width == int.MinValue)
            _width = miGetInt("Width");
        return _width;
    }
}

// ... (Elsewhere, in another file) ...
/// <summary>Returns a MediaInfo value as an int, 0 if error.</summary>
/// <param name="parameter">The MediaInfo parameter.</param>
public int miGetInt(string parameter) {
    int parsedValue;
    string miResult = mediaInfo.Get(streamKind, id, parameter);
    int.TryParse(miResult, out parsedValue);
    return parsedValue;
}
Run Code Online (Sandbox Code Playgroud)

我的问题是:你是如何处理这样的情况,系统是层次结构但不完全?您是否找到了一个相当优雅的策略,或者只是接受了并非每个简单的问题都有一个?

And*_*nan 5

我认为你最好使用接口组合,如果实现比一堆属性更复杂,那么组合提供接口的共享实现:

abstract class Media  {
 // General properties/functions
}

class VideoAndImageCommon { // Crappy name but you get the idea
 // Functions used by both video and images
}

interface IVideoAndImageCommon {
 // Common Video & Image interface
}

class Video : Media, IVideoAndImageCommon {
  private readonly VideoAndImageCommon _commonImpl = new VideoAndImageCommon();

  // Implementation of IVideoAndImageCommon delegates to _commonImpl.
}

class Image : Media, IVideoAndImageCommon {
  private readonly VideoAndImageCommon _commonImpl = new VideoAndImageCommon();

  // Implementation of IVideoAndImageCommon delegates to _commonImpl.
}
Run Code Online (Sandbox Code Playgroud)