2009-03-08 21 views
6

Sto progettando una libreria di classi riutilizzabile che contiene 2 assembly (tra gli altri) denominati core.xml.dll e core.string.dll.Dipendenze circolari rispetto a DRY

L'assembly xml fa riferimento all'assembly di stringhe per utilizzare alcuni metodi di stringa helper.

Tuttavia ora esiste un metodo di stringa che potrebbe trarre vantaggio dall'utilizzo di un metodo contenuto nell'assembly xml.

Se faccio riferimento all'assembly xml dall'assieme di stringhe, avrò creato una dipendenza circolare e non sarà possibile creare entrambi gli assembly dal codice sorgente. (cioè il problema del pollo e dell'uovo).

Per seguire il principio "Non ripetere se stessi", vorrei evitare di duplicare la funzionalità in entrambi gli assiemi. Se trovo un bug nell'implementazione, voglio solo sistemarlo in un posto.

Mentre potevo unire i gruppi in uno, questo non è l'ideale in quanto riduce la coesione dell'assieme.

Avrei bisogno di ricostruire e ridistribuire l'intero assieme solo per una piccola modifica a una classe specifica. Inoltre, alla fine, con così tante dipendenze probabilmente finirei con un enorme assemblaggio di librerie.

Quindi, nel contesto di un insieme riutilizzabile di gruppi di librerie qual è l'approccio migliore da utilizzare qui? Inoltre, in che modo lo stesso framework .NET si occupa di questo problema?

(riflettore sembra che fa riferimento a System.Configuration.dll System.xml.dll e viceversa. E 'questo in realtà corretta, se sì, come viene gestita la dipendenza circolare?)

+0

Puoi fornire un esempio concreto di come un metodo "... stringa che trarrebbe vantaggio dall'utilizzo di un metodo contenuto nell'assembly xml." –

+0

Stavo guardando un metodo di conversione che accetta XML e converte in un formato basato su stringhe Sì, sto pensando che questo potrebbe essere gestito in modo diverso in qualche modo, tuttavia sono ancora interessato alla domanda più generale – Ash

+0

il libro di John Lakos, "Progettazione di software C++ su larga scala". Un sacco di quel materiale potrebbe essere inapplicabile a C#, ma approfondisce l'architettura livellata, che è esattamente quello che sta facendo la tua domanda. – Tom

risposta

6

Accetto con Coltelli. Le defezioni circolari sono un odore di design. Rifattalo senza pietà!

Questo può essere difficile nel caso in cui gli oggetti aziendali siano strettamente accoppiati. Nella maggior parte dei casi questo può essere risolto attraverso l'iniezione di dipendenza.

Pseudo C++ Esempio:

class Employee { 
    Company company; 
}; 

class Company { 
    vector<Employee> employees; 
}; 

Tricky? Non neccesarily:

template<class CompanyT> 
class Employee { 
    CompanyT company; 
}; 

class Company { 
    vector<Employee<Company> > employees; 
}; 

tipi più primitivi, che deve dipendere da un livello più alto, possono essere astratte di lavorare con qualsiasi tipo di altro tipo, a condizione che soddisfi i suoi contratti.

+0

Ma Iv'e ha trovato che le risorse circolari spesso appaiono abbastanza naturalmente in un oggetto design orientato, ovvero il Dipendente lavora per la Società, la Società ha un numero di Dipendenti. Come si refactoring senza cambiare questo tipo di relazione? – Ash

+0

@Ash: l'obiettivo del sistema è il dipendente o l'azienda? Se il primo, quindi il dipendente non è di proprietà della società, la società è solo un aspetto della loro vita. In quest'ultimo caso, l'azienda ha diverse classi di dipendenti, che condividono una o più interfacce comuni. – Shog9

+0

@ Shog9, trovo che creo riferimenti bidirezionali nei miei progetti abbastanza spesso. Ma sembra che tu stia dicendo che questo può essere un odore di design e dovrebbe essere ridotto al minimo. Dovrò pensarci un po 'di più, grazie. – Ash

3

Suona come avete bisogno di un terzo assembly ...

+0

Avevo però un terzo assemblaggio contenente solo Intefaces, ma questo non costringe l'applicazione (client) di entrambi gli assembly a fare tutto il "plug-in" dei componenti insieme? non è necessario un quadro completo per l'iniezione delle dipendenze? – Ash

+1

@Ash - prova a non sovraccaricarlo nella tua testa Se hai bisogno di convertire XML -> String, questo non richiede dipendenza ction, che richiede solo una singola funzione libera (che fa riferimento sia alle librerie String che XML). – Tom

+0

d'accordo con la risposta di Tom, in disaccordo con la necessità di un terzo assemblaggio, è eccessivo quando potrebbe essere solo uno scenario metodo di estensione cioè pensare i metodi di estensione di linq su IEnumerable ... – eglasius

3

Rendilo un metodo di estensione definito nell'assembly xml (basato sul tuo commento "metodo di conversione che accetta XML e converte in un formato basato su stringhe"). Si tratta di xml. Proprio come Linq fa per IEnumerable.

+0

Punta giusta. Ma c'è un approccio di ingegneria del software più generale a questo problema. Il mio esempio con string e xml non è forse il migliore, che dire di un assembly di impostazioni usando l'assembly XML e viceversa? – Ash

+0

@Ash: un modulo XML di base non necessita di alcuna configurazione. Una configurazione basata su XML ha un senso. Un modulo di alto livello che utilizza la configurazione basata su XML per determinare come analizzare altri documenti XML utilizzerà entrambe le librerie. – Tom

3

Se la libreria String richiede realmente la libreria XML, è probabilmente un'indicazione che la libreria String deve essere sottoposta a refactoring in una definizione di tipo di dati di livello inferiore e "utilità principali" (nessuna dipendenza esterna, se possibile) e un'altra libreria di livello superiore che può introdurre XML, SQL, espressioni regolari o qualsiasi altra cosa utile a livello di applicazione.

+0

Buoni consigli, grazie. – Ash

Problemi correlati