Чистая / луковая архитектура в основном вопросе .NET

У меня есть несколько вопросов относительно чистой / луковой архитектуры. Я читал документацию Microsoft, и в ней говорится, что ядро ​​приложения находится в центре, а внешние уровни указывают внутрь в терминах «зависимостей». введите описание изображения здесь

Что именно они имеют в виду, когда это зависит от этого в данном контексте? Когда я думаю о зависимостях, я думаю, что класс B создается внутри класса A, поэтому класс A зависит от класса B. Однако, когда я смотрю на репозиторий eShopOnWeb (https://github.com/dotnet-architecture/eShopOnWeb), похоже, что в ядре архитектуры есть репозитории, которые реализуются в инфраструктуре как зависимости, разве это не противоречие?


person Jon Sherman    schedule 29.04.2020    source источник
comment
Ключевым моментом здесь является принцип инверсии зависимостей и связанные с ним шаблоны реализации. Я рекомендую потратить некоторое время на понимание этого в качестве отправной точки.   -  person grantn    schedule 10.02.2021


Ответы (2)


A зависит от B в этом контексте означает: A знает о B.

Типы внутренних кругов могут использоваться типами внешних кругов, но не наоборот.

Пожалуйста, также обратитесь к: https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html.

person plainionist    schedule 10.08.2020

... похоже, что в ядре архитектуры есть репозитории, которые реализуют инфраструктуру как зависимости, не противоречит ли это?

Здесь вам не хватает интерфейсов. Возьмем OrderService на уровне ядра приложения:

namespace Microsoft.eShopWeb.ApplicationCore.Services
{
    public class OrderService : IOrderService
    {
        private readonly IAsyncRepository<Order> _orderRepository;
        private readonly IUriComposer _uriComposer;
        private readonly IAsyncRepository<Basket> _basketRepository;
        private readonly IAsyncRepository<CatalogItem> _itemRepository;

        public OrderService(IAsyncRepository<Basket> basketRepository,
            IAsyncRepository<CatalogItem> itemRepository,
            IAsyncRepository<Order> orderRepository,
            IUriComposer uriComposer)
        {
            _orderRepository = orderRepository;
            _uriComposer = uriComposer;
            _basketRepository = basketRepository;
            _itemRepository = itemRepository;
        }

        public async Task CreateOrderAsync(int basketId, Address shippingAddress)
        {
            var basketSpec = new BasketWithItemsSpecification(basketId);
            var basket = await _basketRepository.FirstOrDefaultAsync(basketSpec);

            Guard.Against.NullBasket(basketId, basket);
            Guard.Against.EmptyBasketOnCheckout(basket.Items);

            var catalogItemsSpecification = new CatalogItemsSpecification(basket.Items.Select(item => item.CatalogItemId).ToArray());
            var catalogItems = await _itemRepository.ListAsync(catalogItemsSpecification);

            var items = basket.Items.Select(basketItem =>
            {
                var catalogItem = catalogItems.First(c => c.Id == basketItem.CatalogItemId);
                var itemOrdered = new CatalogItemOrdered(catalogItem.Id, catalogItem.Name, _uriComposer.ComposePicUri(catalogItem.PictureUri));
                var orderItem = new OrderItem(itemOrdered, basketItem.UnitPrice, basketItem.Quantity);
                return orderItem;
            }).ToList();

            var order = new Order(basket.BuyerId, shippingAddress, items);

            await _orderRepository.AddAsync(order);
        }
    }
}

OrderService, который определен в ядре приложения, имеет только зависимости от интерфейсов, которые также определены в ядре приложения. .

Например, есть

private readonly IAsyncRepository<Order> _orderRepository;

который вводится в конструктор OrderService.

реализация OrderRepository определяется на уровне инфраструктуры:

namespace Microsoft.eShopWeb.Infrastructure.Data
{
    public class OrderRepository : EfRepository<Order>, IOrderRepository
    {
        public OrderRepository(CatalogContext dbContext) : base(dbContext)
        {
        }

        public Task<Order> GetByIdWithItemsAsync(int id)
        {
            return _dbContext.Orders
                .Include(o => o.OrderItems)
                .Include($"{nameof(Order.OrderItems)}.{nameof(OrderItem.ItemOrdered)}")
                .FirstOrDefaultAsync(x => x.Id == id);
        }
    }
}

Класс инфраструктуры OrderRepository следует контракту IOrderInterface, определенному на уровне Application Core. IOrderRepository снова является производным от IAsyncRepository, который также определен на уровне Application Core.

Я предполагаю, что причина, по которой они используют IAsyncRepository, а не IOrderRepository в OrderService, заключается в том, что к настоящему времени метод OrderService обращается только к методам, определенным базовым интерфейсом IAsyncRepository.

Но идея остается той же: все на уровне ядра приложения должно иметь зависимости только от материалов того же уровня. Затем конкретные реализации вводятся во время выполнения посредством внедрения зависимостей. Но самому уровню Application Core никогда не нужно ничего знать о реальной реализации, находящейся на уровне инфраструктуры.

И если вы последуете этому подходу, утверждение

... ядро ​​приложения находится в центре, а внешние уровни указывают внутрь с точки зрения зависимостей.

остается верным, поскольку внешние уровни зависят от классов и интерфейсов из Application Core, а Application Core зависит только от - Application Core.

person afh    schedule 11.08.2020