Zurück Geschichte:.NET Refactoring, DRY. duale Vererbung, Datenzugriff und Trennung von Bedenken
So habe ich auf ein Architekturproblem für die letzten paar Nächte auf einem Refactor stecken, mit dem ich gespielt habe. Nichts Wichtiges, aber es stört mich. Es ist tatsächlich eine Übung in DRY, und ein Versuch, es so extrem zu nehmen, wie die DAL-Architektur ist vollständig DRY. Es ist eine vollkommen philosophische/theoretische Übung.
Der Code basiert teilweise auf einem der Refactorings von @JohnMacIntyre, die ich vor kurzem davon überzeugt habe, unter http://whileicompile.wordpress.com/2010/08/24/my-clean-code-experience-no-1/ zu bloggen. Ich habe den Code leicht modifiziert, wie ich es tendiere, um den Code eine Ebene weiter zu bringen - normalerweise, um zu sehen, welche zusätzlichen Kilometer ich aus einem Konzept herausholen kann ... jedenfalls sind meine Gründe weitgehend irrelevant.
Teil meiner Datenzugriffsschicht auf die folgende Architektur zugrunde:
abstract public class AppCommandBase : IDisposable { }
Dieses enthält grundlegende Dinge, wie die Schaffung eines Befehlsobjekt und Bereinigung nach dem AppCommand entsorgt. Alle meine Kommandobasisobjekte sind davon abgeleitet.
Dies enthält grundlegende Dinge, die alle Lese-Befehle betrifft - speziell in diesem Fall das Lesen von Daten aus Tabellen und Ansichten. Keine Bearbeitung, keine Aktualisierung, kein Speichern.
abstract public class ReadItemCommandBase<T, FilterT> : ReadCommandBase<T, T> { }
Diese enthält einige weitere grundlegende allgemeine Sachen - wie Definition von Methoden, die als ein einzelnes Element aus einer Tabelle in der Datenbank, in der die Tabellennamen, Schlüsselfeldnamen und Feldlistennamen sind definiert lesen erforderlich sein wird, erforderlich abstrakte Eigenschaften (zum von der abgeleiteten Klasse definiert werden.
public class MyTableReadItemCommand : ReadItemCommandBase<MyTableClass, Int?> { }
Dies enthält spezifische Eigenschaften, die meine Tabellennamen, um die Liste der Felder aus der Tabelle oder die Ansicht, der Name des Schlüsselfelds zu definieren, ein Verfahren zum parsen die Daten aus der IDataReader-Zeile in mein Geschäftsobjekt und eine Methode, die den gesamten Prozess initiiert.
Nun, ich habe auch diese Struktur für meine Readlist ...
abstract public ReadListCommandBase<T> : ReadCommandBase<T, IEnumerable<T>> { }
public class MyTableReadListCommand : ReadListCommandBase<MyTableClass> { }
Der Unterschied ist, dass die Liste Klassen Eigenschaften enthalten, die Generation gehören zur Liste (d PageStart, PageSize, Sort und gibt eine IEnumerable) vs. Rückgabe eines einzelnen DataObject zurück (das erfordert nur einen Filter, der einen eindeutigen Datensatz identifiziert).
Problem:
Ich hasse, dass ich ein paar Eigenschaften in meiner MyTableReadListCommand Klasse habe, die in meiner MyTableReadItemCommand Klasse identisch sind. Ich habe darüber nachgedacht, sie in eine Hilfsklasse zu verschieben, aber während dies die Mitgliederinhalte an einer Stelle zentralisieren kann, habe ich immer noch identische Mitglieder in jeder der Klassen, die stattdessen auf die Hilfsklasse verweisen, die ich immer noch nicht mag.
Mein erster Gedanke war Dual-Vererbung würde dies gut lösen, auch wenn ich stimme, dass Dual-Vererbung ist in der Regel ein Code-Geruch - aber es würde dieses Problem sehr elegant lösen. Also, da .NET keine doppelte Vererbung unterstützt, wohin gehe ich von hier?
Vielleicht wäre ein anderer Refactor besser geeignet ...aber ich habe Probleme, meinen Kopf darum zu wickeln, wie ich dieses Problem umgehen kann.
Wenn jemand eine vollständige Code-Basis benötigt, um zu sehen, worüber ich rede, habe ich eine Prototyp-Lösung auf meiner DropBox unter http://dl.dropbox.com/u/3029830/Prototypes/Prototype%20-%20DAL%20Refactor.zip. Der betreffende Code befindet sich im DataAccessLayer-Projekt.
P.S. Dies ist nicht Teil eines laufenden aktiven Projekts, es ist eher ein Refaktor-Puzzle für meine eigene Unterhaltung.
Vielen Dank im Voraus Leute, ich schätze es.
Als Referenz wird die Lösung, die Sie nicht mögen, als das Delegationsmuster bekannt: http://en.wikipedia.org/wiki/Delegation_pattern. –
Auch: http://stackoverflow.com/questions/1224830/difference-between-strategy-pattern-and-delegation-pattern.Ich mag es, wie mson das Muster annimmt: "Delegierung bedeutet, dass ein einzelnes Objekt nicht für alles zuständig ist, sondern Verantwortlichkeiten auf andere Objekte delegiert. Der Grund dafür ist, dass es zwei grundlegendere Prinzipien der Softwareentwicklung durchsetzt durch Verringerung der Kopplung und Erhöhung der Kohäsion. " –
Ich bin mir nicht sicher, ob es besser ist, dieses Design zu verwerfen und ein völlig neues zu entwickeln, oder es umzuformen, um etwas Sinnvolles zu finden. Die zunehmende Verwendung von Generika als Typparameter innerhalb einer generischen Definition ist ein sicheres Zeichen, dass Sie eine sehr feine Grenze zwischen Klarheit und Wahnsinn ziehen. Ich bin versucht zu sagen "benutze NHibernate ..." oh warte da, ich sagte es ... –