Ho eseguito in questo più volte, così vorrebbe usare un esempio reale e ottenere idee su come più esperti sviluppatori C# gestire questa situazione.progettazione di classe per il sistema, che è gerarchica, ma non così ordinatamente
Sto scrivendo un wrapper .NET attorno alla libreria non gestita MediaInfo, che raccoglie vari dati sui file multimediali (filmati, immagini ...).
MediaInfo ha molte funzioni, ogni applicazione a diversi tipi di file. Ad esempio, "PixelAspectRatio" si applica a immagini e video ma non a audio, sottotitoli o altri.
Un sottoinsieme delle funzionalità mi piacerebbe avvolgere è qui sotto:
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
Come si può vedere, l'inizio di una mappatura di classe non troppo male sarebbe una classe per la funzionalità specifiche per ogni tipo di flusso e una classe base con funzionalità comuni a tutti i tipi.
Allora questo percorso diventa un po 'meno ovvio. Esistono molte funzioni comuni ai tipi di stream {general, video, audio, text e image}. Va bene, quindi credo che posso fare una classe con un nome puzzolente come "GeneralVideoAudioTextImage", e poi un altro di nome GeneralVideoAudioText (che eredita da GeneralVideoAudioTextImage) per la funzionalità comune a queste cose, ma non "Immagine" corsi d'acqua. Ciò, secondo me, seguirebbe maldestramente la regola "is a" delle gerarchie di classi.
questo è già senza guardare elegante, ma poi ci sono quei casi occasionali come "larghezza", che non rientrano in un gruppo che è in modo pulito un sottoinsieme di un altro gruppo. Questi casi possono semplicemente duplicare la funzionalità laddove necessario - implementarli singolarmente in Video, Testo e Immagine, ma ciò ovviamente violerebbe lo DRY.
Un primo approccio comune sarebbe MI, che C# non supporta. La solita risposta a questo sembra essere "usa MI con interfacce", ma non riesco a trovare del tutto in che modo possa seguire ASCIUTTO. Forse il mio fallimento.
gerarchie di classe sono stati discussi su SO prima, come hanno alternatives a MI (metodi di estensione, ecc), ma nessuna di queste soluzioni sembrava una buona forma. Ad esempio, i metodi di estensione sembrano meglio utilizzati per le classi di cui non è possibile modificare l'origine, come la classe String, e sono più difficili da individuare perché non sono realmente legate alla classe, sebbene possano funzionare. Non ho trovato una domanda su una situazione come questa, anche se questo è probabilmente un fallimento del mio utilizzo dello strumento di ricerca.
Un esempio di una caratteristica MediaInfo, avvolto, potrebbe essere:
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;
}
La mia domanda è: Come hai gestito situazioni come questa, sistemi che sono tipo-di-gerarchico-ma-non-proprio? Hai trovato una strategia abbastanza elegante, o hai semplicemente accettato che non tutti i semplici problemi ne hanno uno?
Se non si trova una soluzione migliore, forse codegen utilizzando CodeDOM o Roslyn potrebbe aiutare. – svick