Onde definir as interfaces para um repositório em uma arquitetura em camadas?

fundo

Eu estou tentando criar um aplicativo simples para realmente entender toda a pilha de DDD + TDD + etc. Meu objetivo é injetar dinamicamente as classes do repositório DAL no tempo de execução. Isso mantém minhas camadas de domínio e serviços de aplicativos testáveis. Eu planejo usar o "pobre homem DI" para realizar isso por enquanto ... então eu faria isso em um aplicativo de console simples perto de inicialização:

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

Para realizar essa injeção de dependência, criei três interfaces de repositório:

-- ICustomerRepository
-- IOrderRepository
-- IProductRespository

Uma implementação típica:

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

** Observe que SaveCustomer faz referência à classe de modelo Customer definida na camada de domínio. Isso é típico dos outros repositórios.

No entanto, não tenho certeza de qual projeto / camada eles devem ser implementados. Tenho 5 projetos em uma solução:

SimpleOrder.ConsoleClient (apresentação) - Eu quero injetar a implementação específica do domínio daqui como o aplicativo

SimpleOrder.ApplicationFacade (serviços de aplicativos) - métodos robustos de nível mais elevado e grosseiro que orquestram métodos de nível inferior no domínio

SimpleOrder.Contracts - Classes DTO usadas para comunicação entre apresentação e serviços de aplicativos

SimpleOrder.Domain (domínio / bll) - classes de modelo de domínio Customer, Order, OrderItem, Product

SimpleOrder.Repository (dal) - implementa as interfaces do repositório

Aqui estão minhas opções como eu vejo:

Opção 1: Defina as interfaces do repositório em SimpleOrder.Contracts ...

PRO: é aqui que eupensar eles devem pertencer porque eu criei isso para compartilhar contratos entre várias preocupações / camadas. ex., os DTOs são definidos aqui.

CON: no entanto, as assinaturas de método de cada interface fazem referência a classes de modelo de domínio.
Isso significa que eu teria que adicionar uma referência ao SimpleOrder.Domain, mas quando o SimpleOrder.Contracts é referenciado em outro projeto, ele terá que carregar SimpleOrder.Domain junto para o passeio. Isso não parece certo.

Opção 2: O mesmo cenário acima, mas também defino interfaces para cada classe de modelo de domínio no SimpleOrder.Contracts para que eu possa dividir o acoplamento das interfaces de repositório com as classes de modelo reais.

Exemplo:

    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; }
        }
    }

IMPACTO: Cada classe de modelo de domínio teria que implementar sua interface relacionada. ou seja,

    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: corrige o problema da Opção 1.

CON: Isso explode o número de arquivos (e a complexidade percebida) no projeto porque cada classe de domínio agora tem uma interface associada.

Opção 3: Defina as intefaces do repositório no SimpleOrder.Domain

IMPACTO: Para injetar as classes do repositório concreto na camada de serviços de aplicativo (projeto SimpleOrder.ApplicationFacade) do SimpleOrder.ConsoleClient no tempo de execução, o SimpleOder.ConsoleClient também precisará de uma referência a SimpleOrder.Domain.

PRO: Isso também resolve Opção 1

CON: Eu estava tentando evitar referenciar a camada de domínio diretamente da camada de apresentação, porque agora a camada de apresentação pode saber muito sobre a camada de domínio. Quando eu substituir o aplicativo de console no futuro com um aplicativo WPF ou ASP.NET MVC no futuro, eu corro o risco de que as implementações da camada de apresentação secundária e subseqüente tentem chamar métodos no Modelo em vez da camada Application Services. (No entanto, eu considero isso na Opção 4.)

Opção 4: Coloque as interfaces em SimpleOrder.Domain e, em seguida, faça referência ao SimpleOrder.Domain no SimpleOrder.ConsoleClient.

PRO: Corrige todos os problemas acima.

CON: Isso não parece certo porque eu estaria fornecendo acesso da camada de apresentação diretamente para os métodos de nível inferior na camada de domínio quando eu deveriasó estar fornecendo acesso aos métodos chunky de nível superior no SimpleOrder.ApplicationFacade.

QUESTÃO Eu tentei cada um destes, mas decidi sobre a opção 4, no entanto, que deixa um gosto ruim na minha boca sobre isso. Existe uma opção melhor? Estou no caminho certo aqui?

questionAnswers(2)

yourAnswerToTheQuestion