2010-03-17 10 views
7

ich auf dem besten Ansatz einige Ratschläge in der folgenden Situation verwenden möchte ...N-Tier-Architektur - Struktur mit mehreren Projekten in VB.NET

wird ich eine Windows-Anwendung und eine Web-Anwendung (Präsentation Schichten), die beide auf eine gemeinsame Business-Schicht zugreifen. Die Business-Schicht untersucht eine Konfigurationsdatei, um den Namen der DLL (Datenschicht) zu finden, auf die sie zur Laufzeit einen Verweis erstellen wird (ist dies die beste Vorgehensweise?).

Der Grund für das Erstellen der Referenz zur Laufzeit auf der Datenzugriffsebene besteht darin, dass die Anwendung je nach dem, was der Client verwendet, mit einem anderen 3rd Party Accounting System verbunden ist. Ich hätte also eine separate Datenzugriffsschicht, um jedes Buchhaltungssystem zu unterstützen. Diese könnten separate Setup-Projekte sein, jeder Client würde das eine oder das andere verwenden, sie müssten nicht zwischen den beiden wechseln.

Projekte:

MyCompany.Common.dll - Enthält Schnittstellen, alle anderen Projekte haben einen Verweis auf diese ein.
MyCompany.Windows.dll - Windows Forms-Projekt, Referenzen MyCompany.Business.dll
MyCompany.Web.dll - Website-Projekt, MyCompany.Business.dll Referenzen
MyCompany.Busniess.dll - Geschäft Schicht, Referenzen MyCompany.Data * (zur Laufzeit)
MyCompany.Data.AccountingSys1.dll -. Datenschicht für Abrechnungssystem 1 MyCompany.Data.AccountingSys2.dll - Datenschicht für Abrechnungssystem 2

Das Projekt MyCompany.Common.dll würde alle Schnittstellen enthalten, jedes andere Projekt hätte einen Verweis auf dieses.

Public Interface ICompany 
    ReadOnly Property Id() as Integer 
    Property Name() as String 
    Sub Save() 
End Interface 

Public Interface ICompanyFactory 
    Function CreateCompany() as ICompany 
End Interface 

Das Projekt MyCompany.Data.AccountingSys1.dll und MyCompany.Data.AccountingSys2.dll würde die Klassen wie folgt enthalten:

Public Class Company 
    Implements ICompany 

    Protected _id As Integer 
    Protected _name As String 

    Public ReadOnly Property Id As Integer Implements MyCompany.Common.ICompany.Id 
     Get 
      Return _id 
     End Get 
    End Property 

    Public Property Name As String Implements MyCompany.Common.ICompany.Name 
     Get 
      Return _name 
     End Get 
     Set(ByVal value as String) 
      _name = value 
     End Set 
    End Property 

    Public Sub Save() Implements MyCompany.Common.ICompany.Save 
     Throw New NotImplementedException() 
    End Sub 

End Class 

Public Class CompanyFactory 
    Implements ICompanyFactory 

    Public Function CreateCompany() As ICompany Implements MyCompany.Common.ICompanyFactory.CreateCompany 
     Return New Company() 
    End Function 

End Class 

Das Projekt MyCompany.Business. dll würde die Geschäftsregeln bereitstellen und Daten von der Datenschicht abrufen:

Public Class Companies 

    Public Shared Function CreateCompany() As ICompany 
     Dim factory as New MyCompany.Data.CompanyFactory 
     Return factory.CreateCompany() 
    End Function  

End Class 

Alle Meinungen/Vorschläge würden sehr geschätzt werden.

Antwort

5

Ein paar Kommentare.

Ich würde vermeiden, eine MyCompany.Common.dll Montage zu haben. Diese enden in der Regel mit allen möglichen Dingen, die nichts miteinander zu tun haben, die dann geändert werden müssen und oft eine Neuerstellung aller Ihrer Baugruppen erfordern.

Ich würde Ihre Assemblies mit dem Namen der Anwendung sowie dem Firmennamen benennen. MyCompany.MyApplication.Business.dll ist MyCompany.Business.dll vorzuziehen. Es ist dann einfacher, Anwendungen in Unterabschnitte aufzuteilen und Code aus mehreren Anwendungen wiederzuverwenden.

Es ist am besten, separate Vertragsassemblys für jede Art von Implementierungsassembly zu haben, die Sie haben werden. In Ihrem Fall würde ich folgende vorschlagen: daher nur ein Vertrag Anordnung für den beide Implementierung Baugruppen

MyCompany.MyApplication.Windows-Contract.dll 
MyCompany.MyApplication.Windows.dll 

MyCompany.MyApplication.Web-Contract.dll 
MyCompany.MyApplication.Web.dll 

MyCompany.MyApplication.Business-Contract.dll 
MyCompany.MyApplication.Business.dll 

MyCompany.MyApplication.Data-Contract.dll 
MyCompany.MyApplication.Data.AccountingSys1.dll 
MyCompany.MyApplication.Data.AccountingSys2.dll 

Aus Ihrer Beschreibung scheint es, dass der AccountingSys1 und AccountingSys2 Baugruppen einen gemeinsamen Vertrag teilen.

Vertragsassemblys sollten Ihr Design und nicht Ihre Implementierung darstellen und nur aufgrund von Designänderungen geändert werden. Sie sollten vermeiden, "signifikanten" Code zu haben (um Fehler zu vermeiden), und Sie sollten den Code auf Schnittstellen, Enums, Ausnahmen, Attribute, Ereignisargumente und Strukturen einschränken - alles ohne "signifikanten" Code.

Wenn die Montage Referenzen Einrichtung Sie sollten sicherstellen, dass Baugruppen nur je Vertrag Assemblys verweisen, etwa so:

Data.AccountingSys1 
    Data-Contract 

Data.AccountingSys2 
    Data-Contract 

Business 
    Business-Contract 
    Data-Contract 

Windows 
    Windows-Contract 
    Business-Contract 
    Data-Contract (maybe) 

Web 
    Web-Contract 
    Business-Contract 
    Data-Contract (maybe) 

Als Ergebnis Implementierung Baugruppen nie eine Abhängigkeit von anderen Implementierung Baugruppen haben. Wenn sich eine Implementierung ändert, haben Sie nur eine Assembly neu zu erstellen.

Die Ausnahme von dieser Regel ist beim Erstellen von Vererbungshierarchien. Sie können beispielsweise eine *.Data.AccountingSys.dll erstellen, um Basisklassen für die zwei spezifischen Accounting-System-Assemblies zu definieren.

Wenn Sie alle oben genannten Schritte ausführen können, müssen Sie eine Art von Abhängigkeitsinjektion implementieren, um Instanzen von Objekten aus den Schnittstellen in den Vertragsassemblys erstellen zu können. Sie können ein vorhandenes DI-Framework verwenden oder eine dritte Gruppe von *-Factory.dll Assemblys erstellen, die Ihre Factory-Methoden enthalten.

Ein weiterer Vorteil dieser Art von Struktur ist, dass Komponententests viel einfacher sind und auf den Verträgen anstatt auf der Implementierung basieren können, was Ihnen hilft, sauberen, testbaren Code zu schreiben.

Das mag wie eine Menge Assemblys aussehen, aber die Vorteile, die Sie durch das Vermeiden von unangenehmen Abhängigkeiten vom Code erhalten, verringern die Wahrscheinlichkeit, dass Ihr Projekt zu komplex wird und Ihnen dabei hilft, gute Qualität zu erzielen. Ein kleiner Schmerz wird jetzt so viel Schmerz später beseitigen.

+0

Ich werde es versuchen, danke. –

+0

+1 Sie haben vergessen zu erwähnen, dass nach einer Weile auch die Hälfte einer "Common" -Bibliothek außer Gebrauch ist und niemand es jemals entwirrt. Sie könnten auch an den Ideen interessiert sein (hauptsächlich in meinen Kommentaren IMNSHO) in http://stackoverflow.com/questions/925453/wcf-service-proxy-name-namespace-naming-strategy/2430056#2430056 –

+0

+1 danke! Wir haben gerade etwas Ähnliches implementiert, gut, um andere zu sehen, die es durchdacht haben und zu der gleichen Struktur wie wir gekommen sind. –

1

Ihre allgemeine Ansatz ist solide :)

Sie in Erwägung ziehen könnte alle Schnittstellen in einer separaten Assembly (DLL) setzen (streng die Schnittstelle gesprochen befindet sich zwischen der Business-Logik und der Datenzugriffs Umsetzung - sie die einzige sein sollte Dinge, die Zugang zu der Schnittstelle haben), aber im großen Schema von Dingen, die vielleicht keine so große Sache sind.

Persönlich hätte ich eine gemeinsame Factory-Methode, die ein Objekt zurückgab, und es einfach bei der Verwendung geeignet werfen.

+0

Wenn ich die Schnittstellen in einer separaten Assembly zwischen den Daten und Business-Schichten habe, wie greift die Präsentationsebene auf die Eigenschaften des Company-Objekts, das von der Business-Schicht zurückgegeben wird. Zum Beispiel (von der Präsentationsschicht): Dim Firma As ICompany = MyCompany.Business.Companies.CreateCompany() Damit dies in der Präsentationsschicht funktioniert, muss ein Verweis auf die ICompany Interface-Klasse in der Interface-Baugruppe vorhanden sein. Gibt es einen anderen Weg, dies zu tun? –

+0

focus.nz - werfen Sie einen Blick auf meine Antwort, wie ich denke, ich erkläre es dort. http://stackoverflow.com/questions/2466293/n-tier-architecture-structure-with-multiple-projects-in-vb-net/2467026#2467026 – Enigmativity

+0

@ focus.nz - Die Definition der Schnittstellen hat nicht um an der gleichen Stelle zu sein wie die Definition von Entitäten/Typen, die es verwendet, könnten Sie diese an einer anderen (zentralen) Position (und damit Sichtbarkeit) haben. Es hängt auch davon ab, ob Sie die gleichen Typen zwischen DAL und BL und zwischen BL und UI (zum Beispiel) verwenden möchten. –

1

Es ist ein ausgezeichneter Ansatz!Ich habe es in einem unserer Systeme bei der Arbeit verwendet, und es hat sich als zuverlässig erwiesen, und es ermöglicht uns, bei Bedarf schnell zusätzliche Schnittstellen hinzuzufügen (z. B. wenn wir mit einem anderen Buchhaltungssystem eines von uns erworbenen Unternehmens arbeiten müssen).)

Verwandte Themen