2010-09-15 9 views
23

Se ho questi due progetti:Come gestire i riferimenti circolari?

MyCompany.ERP.Billing 
MyCompany.ERP.Financial 

Fatturazione chiede/invia informazioni al finanziarie e viceversa. Entrambi sono troppo grandi, quindi non voglio metterli in un singolo progetto. Visual Studio non consente riferimenti circolari. Come faresti a trattare con quello?

+3

Mentre è possibile utilizzare diversi trucchi già menzionati, questo sembra un problema architettonico. Come si fa una distinzione tra fatturazione e finanziaria? Trovo un po 'difficile tracciare una battuta qui, e il mio sentimento è "Finanziario" non dovrebbe mai riferirsi alla fatturazione, perché è molto meno astratto. È possibile che alcuni oggetti risiedano nel progetto sbagliato? Che cosa è esattamente "troppo grande"? – mnemosyn

+1

Questo è solo un esempio. L'intenzione è sapere come creare un ERP seguendo le buone pratiche OOP poiché i riferimenti circolari sono molto comuni su quel tipo di software perché è molto grande e suddiviso in molti moduli. – Eduardo

+3

I riferimenti circolari provengono da un design imperfetto non dalla complessità del dominio. Nessun gioco di parole, non sto dicendo che questa è la situazione qui. Gli ERP non sono qualcosa che puoi sviluppare mentre scendi lungo il percorso, devi avere un'immagine molto chiara di ciò che stai cercando di realizzare molto prima di scrivere una singola riga di codice. – devnull

risposta

23

Estrarre le interfacce dalle classi e inserirle in un progetto principale a cui fanno riferimento entrambi i progetti Billing e Financial. È quindi possibile utilizzare tali interfacce per condividere i dati tra gli assiemi.

Questo consente di passare solo agli oggetti tra questi 2 assiemi, ma non è possibile creare oggetti dall'altro poiché in realtà non si dispone di un riferimento per iniziare. Se vuoi essere in grado di creare oggetti hai bisogno di una fabbrica, esterna a quei 2 progetti, che gestisca la creazione dell'oggetto.

Vorrei estrarre la logica aziendale che deve condividere i dati avanti e indietro tra Billing e Financial in un altro progetto. Ciò renderebbe le cose molto più semplici e ti risparmierebbe dal ricorrere a tutti i tipi di trucchi che rendono la manutenibilità un incubo.

+0

E come posso creare istanze di oggetti finanziari all'interno della fatturazione? Esempio: IAccountPayable a = new ???() – Eduardo

+0

Gli oggetti di trasferimento dati che devono essere utilizzati come parametri e i valori di ritorno da passare tra fatturazione e finanziari devono essere definiti nell'assembly condiviso, insieme alle interfacce di servizio. Le implementazioni del servizio sarebbero idealmente costruite tramite un'infrastruttura per le dipendenze e fornite tramite gli argomenti del costruttore alle classi che dipendono da esse. – StriplingWarrior

+0

Sono d'accordo che questa è una possibilità, ma richiede l'utilizzo di un ServiceLayer e DTO (intelligenti). Tuttavia, se l'OP sta implementando DomainModel, ciò non funzionerà. Ma se DomainModel è la strada da percorrere o meno dipende da molti criteri, non è sempre possibile sceglierli come DTO, in cui l'intero approccio porterà a un codice ingombrante. Mi ricorda i molti pericoli che derivano da "Enterprise Integration Patterns" ... – mnemosyn

5

Avere un progetto troppo grande non dovrebbe essere un problema. Puoi mantenere il tuo codice strutturato con namespace e cartelle differenti per il codice sorgente. In questo caso i riferimenti circolari non sono più un problema.

+1

-1. Mentre l'affermazione è * accurata *, manca il punto della domanda. –

+1

Stavo rispondendo alla domanda nella domanda "Entrambi sono troppo grandi, quindi non voglio metterli in un unico progetto". Penso che l'uso di cartelle e spazi dei nomi sia la soluzione corretta per risolvere questo problema. La creazione di ulteriori assembly deve essere eseguita quando è necessario distribuire le parti dell'applicazione in modo indipendente. – PhilB

+3

Uno dei problemi dei progetti di grandi dimensioni è che molte persone apportano modifiche nel file .csproj, causando troppe fusioni. – Eduardo

3

La risposta che menziona le interfacce è corretta, ma se è necessario essere in grado di creare entrambi i tipi da entrambi i progetti, sarà necessario creare una factory in un altro progetto (che farebbe riferimento anche al progetto delle interfacce, ma potrebbe essere referenziato da entrambi i tuoi progetti principali) o cambiare la struttura che stai utilizzando in modo significativo.

Qualcosa del genere dovrebbe funzionare:

Finance: References Billing, Interfaces, Factory 
Billing: References Finance, Interfaces, Factory 
Factory: References Interfaces 

fabbrica avrebbe un BillingFactory.CreateInstance() As Interfaces.IBilling e anche la classe di fatturazione astratta che implementa Interfaces.IBilling.

L'unico problema che posso vedere è se devi fare qualcosa di intelligente quando instanzia un oggetto e non vuoi che quella logica finisca in un progetto separato - ma come non hai menzionato nessuna logica intelligente per istanziare, questo dovrebbe essere sufficiente

+1

Vuoi dire qualcosa del genere? MyCompany.ERP.Factories.Billing.CreateInstance (typeof (IAccountPayable)) – Eduardo

+0

Sì - È quindi responsabilità della fabbrica creare la propria istanza concreta e restituirla. Questo può essere chiamato da qualsiasi altra posizione. Dove la classe AccountPayable astratta che implementa vite IAccountPayable dipenderà da quanto sia complessa - se è semplicemente un POCO, può vivere in un luogo semplice (cioè anziché un progetto di interfacce, avere un progetto comune o di entità). Se è complesso e ha una sua logica, sarà necessario ristrutturare leggermente, poiché non vorrai che tutta la tua logica di business sia dispersa in progetti comuni ... – Basic

+0

Utilizziamo: un assembly Project.BusinessLogic che contiene "Managers" ". I manager sono classi che si occupano di entità in un assembly Project.Entities: l'interfaccia utente dialoga con gestori che mantengono la logica per manipolare le entità. I manager possono manipolare o restituire entità. Le entità nel nostro caso sono POCO molto semplici. I manager hanno anche un metodo CreateInstance() che restituisce una nuova entità. – Basic

0

This solution potrebbe finire come soluzione alternativa per il problema di riferimento circolare. Fondamentalmente si utilizza la logica #if attorno al codice che non viene compilato a meno che il riferimento esista e si utilizza la compilazione condizionale nel file di progetto per definire una variabile solo se esiste l'assembly necessario. Di conseguenza, al primo download dal sorgente o dopo una soluzione pulita, è necessario compilare due volte. Le build/ricostruzioni successive richiedono solo 1 build come di consueto. La cosa bella di questo è che non devi mai commentare/decommentare manualmente le dichiarazioni #define.