Gdzie zdefiniować interfejsy dla repozytorium w architekturze warstwowej?

tło

Próbuję stworzyć prostą aplikację, aby naprawdę zrozumieć cały stos DDD + TDD + itp. Moim celem jest dynamiczne wstrzykiwanie klas repozytorium DAL w czasie wykonywania. Dzięki temu moje warstwy domen i usług aplikacji są testowalne. Planuję teraz używać „DI człowieka biednego”, aby to osiągnąć ... więc zrobiłbym to w prostej aplikacji konsoli w pobliżu uruchamiania:

    // 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);

Aby wykonać ten zastrzyk zależności, stworzyłem trzy interfejsy repozytorium:

-- ICustomerRepository
-- IOrderRepository
-- IProductRespository

Typowa implementacja:

    namespace SimpleOrder.Domain.Interfaces
    {
        public interface ICustomerRepository
        {
            Customer GetCustomerById(int customerId);
            void SaveCustomer(Customer customer);
        }
    }

** Zauważ, że SaveCustomer odwołuje się do klasy modelu klienta zdefiniowanej w warstwie domeny. Jest to typowe dla innych repozytoriów.

JEDNAKŻE nie jestem pewien, który projekt / warstwę należy wdrożyć. Mam 5 projektów w rozwiązaniu:

SimpleOrder.ConsoleClient (prezentacja) - Chcę wprowadzić konkretną implementację domeny z poziomu aplikacji

SimpleOrder.ApplicationFacade (usługi aplikacji) - masywne metody wyższego poziomu, gruboziarniste orkiestrujące metody niższego poziomu w domenie

SimpleOrder.Contracts - Klasy DTO używane do komunikacji między usługami prezentacji i aplikacji

SimpleOrder.Domain (domena / bll) - Klasy modeli domenowych Klient, Zamówienie, Element zamówienia, Produkt

SimpleOrder.Repository (dal) - implementuje interfejsy repozytorium

Oto moje opcje, które widzę:

Opcja 1: Zdefiniuj interfejsy repozytorium w SimpleOrder.Contracts ...

PRO: to jest miejsce gdzie jamyśleć powinny należeć do nich, ponieważ stworzyłem to, aby dzielić umowy między różnymi koncernami / warstwami. np. DTO są tutaj zdefiniowane.

CON: jednak podpisy metod w każdym interfejsie odwołują się do klas modeli domeny.
Oznacza to, że musiałbym dodać odwołanie do domeny SimpleOrder.Domain, ale gdy odwołano się do SimpleOrder.Contracts w innym projekcie, będzie ona musiała przenosić SimpleOrder.Domain razem do jazdy. To nie jest w porządku.

Opcja 2: Taki sam scenariusz jak powyżej, ale określam również interfejsy dla każdej klasy modelu domeny w SimpleOrder.Contracts, dzięki czemu mogę przerwać połączenie interfejsów repozytorium z rzeczywistymi klasami modeli.

Przykład:

    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: Każda klasa modelu domeny musiałaby implementować swój powiązany interfejs. to znaczy.,

    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: Naprawia problem z opcją 1.

CON: Wybiera liczbę plików (i postrzeganą złożoność) w projekcie, ponieważ każda klasa domeny ma teraz powiązany interfejs.

Opcja 3: Zdefiniuj interfejsy repozytorium w SimpleOrder.Domain

IMPACT: Aby wstrzyknąć konkretne klasy repozytorium do warstwy usług aplikacji (SimpleOrder.ApplicationFacade) z SimpleOrder.ConsoleClient w czasie wykonywania, SimpleOder.ConsoleClient będzie również potrzebował odwołania do SimpleOrder.Domain.

PRO: To RÓWNIEŻ rozwiązuje opcję 1

CON: Starałem się unikać bezpośredniego odwoływania się do warstwy domeny z warstwy prezentacji, ponieważ teraz warstwa prezentacji może wiedzieć zbyt wiele o warstwie domeny. Kiedy w przyszłości zastąpię aplikację konsolową aplikacją WPF lub ASP.NET MVC, ryzykuję drugą i kolejne implementacje warstwy prezentacji od próby wywołania metod w modelu zamiast warstwy usług aplikacji. (Jednak rozważam to w Opcji 4.)

Opcja 4: Umieść interfejsy w SimpleOrder.Domain, a następnie odwołaj się do SimpleOrder.Domain z SimpleOrder.ConsoleClient.

PRO: Naprawia wszystkie powyższe problemy.

CON: To nie jest właściwe, ponieważ zapewniłbym dostęp z warstwy prezentacji bezpośrednio do metod niższego poziomu w warstwie domeny, gdy powinienemtylko zapewniać dostęp do masywnych metod wyższego poziomu w SimpleOrder.ApplicationFacade.

PYTANIE Próbowałem każdego z nich, ale zdecydowałem się na opcję 4, JEDNAKŻE jednak pozostawia to w ustach zły smak. Czy jest lepsza opcja? Czy jestem tutaj na dobrej drodze?

questionAnswers(2)

yourAnswerToTheQuestion