Design Pattern - DLL per strategia

7

Di solito mi sono trovato a progettare la mia applicazione nel modo seguente:

  1. Una DLL contenente interfacce per un sottosistema desiderato. Ad esempio, Company.Framework.Persistence.dll .
  2. Una nuova DLL per ogni strategia (o implementazioni ) del suddetto sottosistema. Per esempio:
    • Company.Framework.Persistence.MSSQL.dll
    • Company.Framework.Persistence.MySQL.dll
    • Company.Framework.Persistence.FileSystem.dll

Ciò si tradurrà in una soluzione molto grande con molti progetti, ma d'altra parte darebbe al consumatore la possibilità di scegliere la DLL appropriata per le sue esigenze.

Se avessimo una singola DLL chiamata Company.Framework.Persistence.dll , il consumatore dovrebbe caricare un sacco di strategie che non potrà mai utilizzare. Avere una DLL modularizzata risolverebbe questo problema.

Questa è una buona pratica? C'è uno svantaggio con questo design?

    
posta Matias Cicero 29.05.2015 - 13:59
fonte

3 risposte

2

Penso che i vantaggi di questo approccio siano di gran lunga superiori a qualsiasi svantaggio.

Quello che stai ottenendo qui è più o meno una perfetta "implementazione" del I in SOLID con il pattern Stairway - vale a dire, l'applicazione dipende "in basso" su un'interfaccia definito in Company.Framework.Persistence.dll e anche le singole implementazioni dipendono "su" da questa astrazione.

Questo significa che la tua applicazione è molto disaccoppiata da qualsiasi dettaglio di implementazione (ovviamente vorresti comporre il grafico di runtime attuale usando un container IOC di qualche tipo) Ho spudoratamente collegato a un'immagine esistente di questo modello da un'altra risposta sull'argomento su Stack Overflow:

Nellibro Adaptive Code tramite C # l'autore parla di questo approccio e lo chiama specificatamente come qualcosa che dovrebbe sempre essere fatto perché fornisce un livello così alto di disaccoppiamento. ( esempio )

Un altro possibile vantaggio è la possibilità di applicare patch alle implementazioni individuali senza preoccuparsi di averne influenzato altre, anche se questo è abbastanza limitato una volta che sei stato diligente con i tuoi test di regressione; anche la possibilità di implementare le singole implementazioni in sottocartelle che possono contenere anche le versioni specifiche di eventuali dipendenze di terze parti di cui potrebbero aver bisogno probabilmente aiuterà a mantenere le cose ben organizzate.

L'unico vero svantaggio che posso pensare con questo approccio è che è possibile in teoria cambiare l'interfaccia in Company.Framework.Persistence.dll (insieme ai binari dell'applicazione) e trascurare di aggiornare le corrispondenti DLL di implementazione che porteranno a errori di runtime per i tuoi utenti.

Essendo stato colpevole di aver fatto esattamente questo in passato, posso dire che questo è davvero qualcosa che può accadere se sei molto distratto:)

    
risposta data 30.05.2015 - 13:47
fonte
1

Lo faccio anche io.

I progetti / DLL sono essenzialmente gratuiti e rendono il codice più leggibile e più facile da usare.

Ho saputo che le persone usano una singola grande DLL e si differenziano con gli spazi dei nomi. Ma come tu dici che devono distribuire il codice inutilizzato, non vedo alcun beneficio per la pratica e molti aspetti negativi come

  • passare a un'implementazione richiede la ricompilazione di altri
  • il codice inutilizzato viene distribuito per la vita (rischio di bug)
  • il codice di test viene distribuito in tempo reale (mocket ecc., rischio di bug, errata configurazione)
  • il codice obsoleto richiede il refactoring da rimuovere, (diciamo che non usiamo più MySQL)
  • devono testare il codice non utilizzato prima della distribuzione (stiamo testando giusto?)
  • il refactoring può causare errori di compilazione nel componente non utilizzato (diciamo che cambiamo un'interfaccia)

Potrei tagliare gli angoli e mettere l'implementazione concreta con l'interfaccia per le piccole applicazioni se evita un progetto che contiene solo una singola interfaccia. Ma normalmente trovo le interfacce andare con i modelli. Quindi avrei

  • Company.Framework.Models.dll (include l'interfaccia per la persistenza)
  • Company.Framework.Persistence.MySQL.dll (ref Models, ma deve comunque)
  • Company.Framework.Persistence.Mock.dll (ref Models, ma deve comunque)

o (cattiva scelta!)

  • Company.Framework.Models.dll (non incluse le interfacce)
  • Company.Framework.Persistence.MySQL.dll (include l'interfaccia di persistenza, i modelli ref)
  • Company.Framework.Persistence.Mock.dll (modelli ref e sql, ma non distribuiti per la vita)

Obvs, è piuttosto semplice da rifattorizzare le interfacce se l'applicazione aumenta di dimensioni / complessità

    
risposta data 29.05.2015 - 14:32
fonte
0

Il vantaggio della strategia due è di ridurre al minimo l'inferno di dll.

Solitamente Company.Framework.Persistence.MySQL.dll dipenderà da qualche dll per l'interfaccia con MySql. Se non ho interesse per MySql, perché dovrei scaricare la DLL da MySql?

Diciamo che il tuo framework supportava 20 diversi fornitori di storage. La maggior parte degli utenti ne usa solo uno. Quindi tutti gli utenti devono andare a prendere 19 dll che non useranno mai solo per compilare il framework.

Seguendo la strategia due, permetti ai tuoi utenti di installare solo le DLL che useranno e quindi ridurranno al minimo l'inferno.

    
risposta data 29.05.2015 - 15:03
fonte