¿Dónde definir las interfaces para un repositorio en una arquitectura en capas?

Fondo

Estoy tratando de crear una aplicación simple para entender realmente la pila completa de DDD + TDD +, etc. Mi objetivo es inyectar dinámicamente las clases de repositorio DAL en tiempo de ejecución. Esto mantiene mis capas de Dominio y Servicios de Aplicación verificables. Planeo usar "DI de los hombres pobres" para lograr esto por ahora ... así que lo haría en una aplicación de consola simple cerca del inicio:

    // 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 lograr esta inyección de dependencia, he creado tres interfaces de repositorio:

-- ICustomerRepository
-- IOrderRepository
-- IProductRespository

Una implementación típica:

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

** Tenga en cuenta que SaveCustomer hace referencia a la clase de modelo de Cliente definida en la capa de dominio. Esto es típico de los otros repositorios.

SIN EMBARGO, no estoy seguro de en qué proyecto / capa deberían implementarse. Tengo 5 proyectos en una solución:

SimpleOrder.ConsoleClient (presentación) - Quiero inyectar la implementación específica del dominio desde aquí como la aplicación.

SimpleOrder.ApplicationFacade (servicios de aplicación) - Métodos gruesos de nivel superior y de grano grueso que organizan métodos de nivel inferior en el dominio.

SimpleOrder.Contracts - Clases DTO utilizadas para la comunicación entre servicios de presentación y aplicación.

SimpleOrder.Domain (domain / bll) - clases de modelo de dominio Cliente, Pedido, Artículo de pedido, Producto

SimpleOrder.Repository (dal) - Implementa las interfaces del repositorio.

Aquí están mis opciones como lo veo:

Opción 1: Defina las interfaces del repositorio en SimpleOrder.Contracts ...

PRO: aquí es donde yopensar deberían pertenecer porque creé esto para compartir contratos entre varias preocupaciones / capas. ej., los DTO se definen aquí.

CON: sin embargo, las firmas del método en cada interfaz hacen referencia a las clases de modelo de dominio.
Esto significa que tendría que agregar una referencia a SimpleOrder.Domain, pero cuando se hace referencia a SimpleOrder.Contracts en otro proyecto, tendrá que llevar a SimpleOrder.Domain a lo largo del viaje. Esto no se siente bien.

Opcion 2: El mismo escenario que el anterior, pero TAMBIÉN defino interfaces para cada clase de modelo de Dominio en SimpleOrder.Contracts, por lo que puedo romper el acoplamiento de las interfaces del repositorio con las clases de modelo reales.

Ejemplo:

    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 clase de modelo de dominio tendría que implementar su interfaz relacionada. es decir.,

    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 el problema de la Opción 1.

CON: Esto explota la cantidad de archivos (y la complejidad percibida) en el proyecto porque cada clase de dominio ahora tiene una interfaz asociada.

Opción 3: Defina las interfaces del repositorio en SimpleOrder.Domain

IMPACTO: Para inyectar las clases de repositorio concretas en la capa de servicios de aplicación (proyecto SimpleOrder.ApplicationFacade) desde SimpleOrder.ConsoleClient en tiempo de ejecución, SimpleOder.ConsoleClient TAMBIÉN necesitará una referencia a SimpleOrder.Domain.

PRO: Esto también resuelve la Opción 1

CON: Estaba tratando de evitar hacer referencia directamente a la capa de dominio desde la capa de presentación porque ahora la capa de presentación puede saber demasiado sobre la capa de dominio. Cuando reemplace la aplicación de la consola en el futuro con una aplicación WPF o ASP.NET MVC en el futuro, me arriesgo a que las implementaciones de la segunda y posterior presentación intenten llamar a métodos en el Modelo en lugar de la capa de Servicios de la Aplicación. (Sin embargo, considero esto en la Opción 4).

Opción 4: Coloque las interfaces en SimpleOrder.Domain, luego haga referencia a SimpleOrder.Domain desde SimpleOrder.ConsoleClient.

PRO: Corrige todos los problemas anteriores.

CON: Esto no se siente bien porque estaría proporcionando acceso desde la capa de presentación directamente a los métodos de nivel inferior en la capa de dominio cuando deberíasolamente proporcionará acceso a los métodos gruesos de nivel superior en SimpleOrder.ApplicationFacade.

PREGUNTA Probé cada uno de estos, pero me decidí por la Opción 4, SIN EMBARGO, eso deja un mal sabor de boca. ¿Hay alguna opción mejor? ¿Estoy en el camino correcto aquí?

Respuestas a la pregunta(2)

Su respuesta a la pregunta