Entwurfsmuster - DLL pro Strategie

8

Normalerweise habe ich meine Anwendung folgendermaßen gestaltet:

  1. Eine DLL mit Schnittstellen für ein gewünschtes Subsystem. Zum Beispiel Company.Framework.Persistence.dll.
  2. Eine neue DLL pro Strategie (oder Implementierung ) des Subsystems. Zum Beispiel:
    • Company.Framework.Persistence.MSSQL.dll
    • Company.Framework.Persistence.MySQL.dll
    • Company.Framework.Persistence.FileSystem.dll

Dies führt zu einer sehr großen Lösung mit vielen Projekten, bietet dem Verbraucher jedoch die Möglichkeit, die für seine Anforderungen geeignete DLL auszuwählen.

Wenn wir eine einzelne DLL Company.Framework.Persistence.dllaufrufen würden, müsste der Verbraucher viele Strategien laden, die er möglicherweise nie verwenden wird. Eine modularisierte DLL würde dieses Problem lösen.

Ist das eine gute Praxis? Gibt es einen Nachteil bei diesem Design?

Matias Cicero
quelle
1
Hat es einen Nachteil, alles einzubeziehen? Computerspeicher ist billig . Ist es wirklich wichtig, solange die Komplexität für den Benutzer gering ist?
2
Sie können jederzeit alle Assemblys in einer Mega-DLL als Build-Schritt zusammenführen: stackoverflow.com/questions/8077570/…
Den
verwandt (ähnlicher Ansatz): codeproject.com/Articles/666492/Dynamic-Load-NET-Assembly
Nick Alexeev

Antworten:

3

Ich denke, dass die Vorteile dieses Ansatzes die Nachteile bei weitem überwiegen.

Was Sie hier erreichen, ist mehr oder weniger eine perfekte "Implementierung" des IIn SOLIDüber das StairwayMuster - das heißt, Ihre Anwendung hängt "down" von einer in definierten Schnittstelle ab Company.Framework.Persistence.dllund die einzelnen Implementierungen selbst hängen auch "up" ab. auf diese Abstraktion.

Dies bedeutet, dass Ihre Anwendung stark von Implementierungsdetails entkoppelt ist (natürlich möchten Sie normalerweise das eigentliche Laufzeitdiagramm mit einem IOC-Container erstellen). Ich habe schamlos mit einem vorhandenen Bild dieses Musters aus einer anderen Antwort zu diesem Thema verknüpft bei Stapelüberlauf:

Beispiel eines Treppenmusters

In dem Buch Adaptive Code via C # spricht der Autor über diesen Ansatz und nennt ihn ausdrücklich etwas, das immer getan werden sollte, weil es ein so hohes Maß an Entkopplung bietet. ( Beispiel )

Ein weiterer möglicher Vorteil besteht darin, dass Sie einzelne Implementierungen patchen können, ohne befürchten zu müssen, dass Sie andere beeinflusst haben. Dies ist jedoch nur ein geringfügiger Vorteil, wenn Sie Ihre Regressionstests sorgfältig durchgeführt haben. Die Möglichkeit, die einzelnen Implementierungen in Unterordnern bereitzustellen, die auch die spezifischen Versionen von Abhängigkeiten von Drittanbietern enthalten können, die sie möglicherweise benötigen, wird wahrscheinlich dazu beitragen, die Dinge gut organisiert zu halten.

Der einzige wirkliche Nachteil, den ich mir bei diesem Ansatz Company.Framework.Persistence.dllvorstellen kann, ist, dass es theoretisch möglich ist, die Benutzeroberfläche (zusammen mit den Binärdateien Ihrer Anwendung) zu ändern und die entsprechenden Implementierungs-DLLs nicht zu aktualisieren, was zu Laufzeitfehlern für Ihre Benutzer führt.

Nachdem ich mich in der Vergangenheit schuldig gemacht habe, kann ich sagen, dass dies wirklich nur etwas ist, was passieren kann, wenn Sie sehr nachlässig sind :)

Stephen Byrne
quelle
1

Ich mache es auch so.

Projekte / DLLs sind im Wesentlichen kostenlos und machen den Code lesbarer und benutzerfreundlicher.

Ich habe gewusst, dass Leute eine einzige große DLL verwenden und mit Namensräumen differenzieren. Aber wie Sie sagen, müssen sie nicht verwendeten Code bereitstellen, sehe ich keine Vorteile für die Praxis und viele Nachteile wie

  • Um zu einer Implementierung zu wechseln, müssen andere neu kompiliert werden
  • Nicht verwendeter Code wird zum Leben bereitgestellt (Fehlerrisiko)
  • Testcode wird live bereitgestellt (Verspottungen usw., Fehlerrisiko, Fehlkonfiguration)
  • Veralteter Code muss zum Entfernen umgestaltet werden (sagen wir, wir verwenden MySQL nicht mehr).
  • müssen nicht verwendeten Code vor der Bereitstellung testen (wir testen richtig?)
  • Refactoring kann zu Kompilierungsfehlern in nicht verwendeten Komponenten führen (sagen wir, wir ändern eine Schnittstelle).

Ich könnte Abstriche machen und die konkrete Implementierung mit der Schnittstelle für kleine Anwendungen versehen, wenn ein Projekt vermieden wird, das nur eine einzige Schnittstelle enthält. Aber normalerweise finde ich, dass die Schnittstellen zu den Modellen passen. Also hätte ich

  • Company.Framework.Models.dll (enthält Schnittstelle für Persistenz)
  • Company.Framework.Persistence.MySQL.dll (ref Modelle, muss aber trotzdem)
  • Company.Framework.Persistence.Mock.dll (ref Models, muss aber trotzdem)

oder (schlechte Abkürzung!)

  • Company.Framework.Models.dll (ohne Schnittstellen)
  • Company.Framework.Persistence.MySQL.dll (einschließlich Persistenzschnittstelle, Referenzmodelle)
  • Company.Framework.Persistence.Mock.dll (Referenzmodelle und SQL, aber nicht zum Leben bereitgestellt)

Es ist ziemlich einfach, die Schnittstellen neu zu gestalten, wenn die Größe / Komplexität der Anwendung zunimmt

Ewan
quelle
0

Der Vorteil von Strategie zwei ist die Minimierung der DLL-Hölle.

Normalerweise hängt Company.Framework.Persistence.MySQL.dll von einer DLL ab, um eine Schnittstelle zu MySql herzustellen. Wenn ich kein Interesse an MySql habe, warum sollte ich die DLL von MySql herunterladen?

Nehmen wir an, Ihr Framework unterstützt 20 verschiedene Speicheranbieter. Die meisten Benutzer verwenden nur einen. Alle Benutzer müssen also 19 DLLs abrufen, die sie niemals nur zum Kompilieren Ihres Frameworks verwenden werden.

Indem Sie Strategie zwei befolgen, erlauben Sie Ihren Benutzern, nur die DLLs zu installieren, die sie verwenden werden, und minimieren so die Hölle der DLLs.

Esben Skov Pedersen
quelle