Фон
Я пытаюсь создать простое приложение, чтобы действительно понять весь стек DDD + TDD + и т.д. Моя цель - динамически вводить классы репозитория DAL во время выполнения. Это помогает мне Доменные и прикладные службы. Я планирую использовать "бедного человека DI" для достижения это на данный момент... поэтому я бы сделал это в простом консольном приложении около запуска:
// Poor man 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);
Чтобы выполнить эту инъекцию зависимостей, я создал три интерфейса репозитория:
-- ICustomerRepository -- IOrderRepository -- IProductRespository
Типичная реализация:
namespace SimpleOrder.Domain.Interfaces { public interface ICustomerRepository { Customer GetCustomerById(int customerId); void SaveCustomer(Customer customer); } }
** Обратите внимание, что SaveCustomer ссылается на класс модели клиента, определенный на уровне домена. Это типично для других репозиториев.
ОДНАКО Я не уверен, какой проект/слой они должны быть реализованы. У меня есть 5 проектов в решении:
-
SimpleOrder.ConsoleClient(презентация) - Я хочу ввести конкретную реализацию домена отсюда как приложение
-
SimpleOrder.ApplicationFacade(службы приложений) - мелкие более высокоуровневые, более грубые методы, организовывающие методы нижнего уровня в домене
-
SimpleOrder.Contracts - классы DTO, используемые для связи между презентационными и прикладными службами
-
SimpleOrder.Domain(домен/bll) - классы модели домена Customer, Order, OrderItem, Product
-
SimpleOrder.Repository(dal) - реализует интерфейсы репозитория
Вот мои варианты, как я вижу:
Вариант 1: Определите интерфейсы репозитория в SimpleOrder.Contracts...
PRO: здесь я думаю, что они должны принадлежать, потому что я создал это для обмена контрактами между различными проблемами/слоями. например, DTO.
CON: однако метод signatures in каждого интерфейса ссылается на классы модели домена.
Это означает, что мне пришлось бы добавить ссылку на SimpleOrder.Domain, но когда
SimpleOrder.Contracts ссылается в другом проекте, ему придется нести
SimpleOrder.Domain для езды. Это не так.
Вариант 2: Тот же сценарий, что и выше, но я также определяю интерфейсы для каждой модели домена класса в SimpleOrder.Contracts, поэтому я могу разбить связь интерфейсов репозитория с фактическими классами моделей.
Пример:
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: каждому классу модели домена придется реализовать свой связанный интерфейс. то есть.,
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: Исправлена проблема с параметром 1.
CON: Это взрывает количество файлов (и воспринимаемую сложность) в проекте, потому что каждый класс домена теперь имеет связанный интерфейс.
Вариант 3: Определите интервал хранилища в SimpleOrder.Domain
IMPACT: Чтобы внедрить конкретные классы репозитория в уровень сервисов приложений (SimpleOrder.ApplicationFacade project) из SimpleOrder.ConsoleClient во время выполнения, SimpleOder.ConsoleClient также потребуется ссылка на SimpleOrder.Domain.
PRO: Это ТАКЖЕ решает вариант 1
CON: Я пытался избежать ссылки на доменный уровень из уровня представления непосредственно, потому что теперь уровень представления может слишком много знать о домене. Когда я буду заменять консольное приложение в будущем с помощью WPF или ASP.NET MVC-приложения в будущем, я рискую реализовать второй и последующие реализации уровня представления, пытаясь вызвать методы в модели вместо уровня приложений. (Однако я рассматриваю это в Варианте 4.)
Вариант 4: Поместите интерфейсы в SimpleOrder.Domain, затем обратитесь к SimpleOrder.Domain из SimpleOrder.ConsoleClient.
PRO: Исправлены все вышеперечисленные проблемы.
CON: Это не очень хорошо, потому что я предоставляю доступ к уровню презентации непосредственно к методам нижнего уровня в доменном слое, когда я должен предоставлять только доступ к более сложным методам более высокого уровня в SimpleOrder.ApplicationFacade.
Вопрос Я пробовал каждый из них, но решил, что на Варианте 4, ОДНАКО, это оставляет мне неприятный вкус. Есть ли лучший вариант? Я на правильном пути здесь?