HintergrundWo definieren Sie die Schnittstellen für ein Repository in einer mehrschichtigen Architektur?
Ich versuche, eine einfache Anwendung zu erstellen, wirklich den ganzen Stapel von DDD zu verstehen + TDD + etc. Mein Ziel ist es, die DAL-Repository-Klassen zur Laufzeit dynamisch zu injizieren. Dies hält meine Domänen- und Anwendungsdienste-Ebenen testbar. Ich plane „armen Mannes DI“ über die Verwendung diese jetzt zu tun ... so würde ich dies in einer einfachen Konsolenanwendung in der Nähe von Startup tun:
// Poor man's DI, injecting DAL repository classes at runtime var productRepository = new SimpleOrder.Repository.ProductRespository(); var customerRepository = new SimpleOrder.Repository.CustomerRepository(); var orderRepository = new SimpleOrder.Repository.OrderRepository(); // Constructor injection into this class in the Application Services layer, // SimpleOrder.ApplicationFacade OrderEntry oe = new OrderEntry(customerRepository, orderRepository, productRepository);
diese Abhängigkeit Injektion zu erreichen, habe ich drei Repository erstellt haben Schnittstellen:
-- ICustomerRepository -- IOrderRepository -- IProductRespository
Eine typische Implementierung:
namespace SimpleOrder.Domain.Interfaces { public interface ICustomerRepository { Customer GetCustomerById(int customerId); void SaveCustomer(Customer customer); } }
** Beachten Sie, dass SaveCustomer die Kundenmodellklasse in der Doma definierten Referenzen in der Schicht. Dies ist typisch für die anderen Repositories.
JEDOCH bin ich nicht sicher, welches Projekt/Schicht sollten sie in realisiert werden Ich habe 5 Projekte in einer Lösung:
SimpleOrder.ConsoleClient (Präsentation) - Ich möchte injizieren. die konkrete Umsetzung der Domain, von hier wie die Anwendung
SimpleOrder.ApplicationFacade (Anwendungsdienste) - klobig auf höherer Ebene, grobkörnig Methoden o rchestrating niedrigere Ebene Methoden in der Domäne
SimpleOrder.Contracts - DTO verwendete Klassen für die Kommunikation zwischen Präsentations- und Anwendungsdienste
SimpleOrder.Domain (Domain/BLL) - domain Modellklassen Kunden, Ordnung, OrderItem, Produkt
SimpleOrder.Repository (dal) - implementiert die repo sitory Schnittstellen
Hier sind meine Optionen, wie ich es sehe:
Option 1: Definieren Sie die Repository-Schnittstellen in SimpleOrder.Contracts ...
PRO: das ist, wo ich denke, sie sollten gehören, weil ich dies erstellt, um Verträge zwischen verschiedenen Anliegen/Schichten zu teilen. zB DTOs sind hier definiert.
CON: aber die Methodensignaturen in jeder Schnittstelle verweist auf Domänenmodellklassen.
Dies bedeutet, dass ich einen Verweis auf die SimpleOrder.Domain hinzufügen müsste, aber wenn die SimpleOrder.Auf Verträge wird in einem anderen Projekt verwiesen, es muss SimpleOrder.Domain für die Fahrt mit sich führen. Das fühlt sich nicht richtig an.
Option 2: gleiches Szenario wie oben, aber ich habe auch definieren Schnittstellen für jede Domain Modell Klasse in dem SimpleOrder.Contracts so kann ich die Kopplung der Repository-Schnittstellen zu den aktuellen Modellklassen brechen.
Beispiel:
namespace SimpleOrder.Domain.Interfaces { public interface ICustomerRepository { ICustomer** GetCustomerById(int customerId); void SaveCustomer(ICustomer customer); } public interface ICustomer { int CustomerId { get; set; } string Name { get; set; } System.Collections.Generic.List Orders { get; } } }
IMPACT: Jede Domain Modellklasse müsste seine zugehörige Schnittstelle implementieren. d. h.
public class Customer : SimpleOrder.Domain.Interfaces.ICustomer { public Customer() { _orders = new List(); } public int CustomerId { get; set; } public string Name { get; set; } private List _orders; public virtual List Orders { get { return _orders; } } }
PRO: Behebt das Problem der Option 1.
CON: Dies explodiert die Anzahl der Dateien (und die wahrgenommene Komplexität) im Projekt, weil jede Domain-Klasse jetzt eine zugehörige Schnittstelle hat.
Option 3: Definieren der Repository intefaces im SimpleOrder.Domain
IMPACT: Um die konkreten Klassen-Repository in die Anwendungsdiensteschicht (SimpleOrder.ApplicationFacade Projekt) von der SimpleOrder.ConsoleClient zur Laufzeit zu injizieren SimpleOder.ConsoleClient benötigt außerdem einen Verweis auf SimpleOrder.Domain.
PRO: Dies löst auch Option 1
CON: Ich habe versucht, die Domain-Schicht von der Präsentationsschicht direkt zu vermeiden verweisen, weil jetzt die Präsentationsschicht über die Domänenschicht zu viel wissen kann. Wenn ich in Zukunft die Konsolenanwendung durch eine WPF- oder ASP.NET MVC-App ersetze, riskiere ich, dass die zweite und nachfolgende Implementierungen der Darstellungsschicht versuchen, Methoden im Modell anstelle der Ebene der Anwendungsdienste aufzurufen. (Allerdings berücksichtige ich dies in Option 4.)
Option 4: Setzen Sie die Schnittstellen in SimpleOrder.Domain, und verweisen Sie dann auf SimpleOrder.Domain von SimpleOrder.ConsoleClient.
PRO: Behebt alle oben genannten Probleme.
CON: Das fühlt sich nicht richtig, weil ich Zugang von der Präsentationsschicht zu den untergeordneten Methoden in der Domänenschicht direkt bereitstellt würde, wenn ich soll nur Zugang zum höheren Ebene klumpigen werden, vorausgesetzt, Methoden in der SimpleOrder.ApplicationFacade.
FRAGE ich jede dieser versucht haben, haben aber auf Option 4 JEDOCH ständiger hinterlässt einen schlechten Geschmack im Mund darüber. Gibt es eine bessere Option? Bin ich hier richtig?
Bei näherer Betrachtung ... sind die Optionen 3 und 4 im Wesentlichen gleich. Hoppla. Ich hätte besser nachlesen sollen. –