3 мая 2019 в 19:21 (МСК)
| сохранено
10 мая 2019 в 19:22 (МСК)
H Змейка на С# и Onion aka Clean Architecture
в черновиках
Tutorial
В прошлой своей статье я вскользь упомянул Onion архитектуру. Там было в основном про то что не надо лишние библиотеки и папки создавать, что надо делить код на модули и что можно писать код прямо в контроллер и использовать Entity Framework там же напрямую
НО Домен все равно должен быть отдельно и все вычисления должны быть в нем. Теперь хочу поговорить о луковой архитектуре. Больше всего подходящей для сложного приложения с большим количеством логики. В этой статье в качестве примера я буду использовать игру "
Змейка " потому что в ней достаточно логики для «богатого» домена
Легенда
Красным цветом указана зависимости.
Зеленым цветом указаны важные группы. Под — слои
Синим цветом разделены основные слоим которые желательно держать отдельно
Терминология
Анемичная модель : Модель данных без логики.
ValueObject : Неизменяемое хранилище данных без уникального идентификатор
Entity : Объект c уникальным идентификатором
Aggregate : Объект содержащий в себе Entity. Обладает уникальным идентификатором.
Data Layer — Repository : Изолирует нас от того что мы используем . Хранилище наших Aggregate
UseCase/Interactor : Изолирует нас от того что использует нас . Например от ASP.NET, gRPC, WCF, WPF, WinForms. Может вызывать Repository когда это нужно. Сам почти ничего не делает и не хранит. Тут должна быть минимальная логика. Только использует Entity, Aggregate, ValueObject и Repository. В Анемичной модели наоборот делает все, тут вся логика.
DomainEvent : Событие которое случилось в Домене и на которое внешний мир должен как-то среагировать. Можно сделать просто булево свойство или коллекцию с объектами у вашего домена в которую добавлять события. Обрабатывать их можно в ApplicationService/UseCase/Interactor.
Суть
Union aka Clean это про то что у вас должен быть отдельно:
Класс, который делает вычисления или является объектным представление какой-то сущности в приложении. Calculator и ResultValueObject
Класс, который пишет данные в хранилище данных или читает их оттуда. CalculatorRepository
Класс, который реагируют на действия пользователя. CalculatorService
Calculator и ResultValueObject должны быть независимы от CalculatorRepository и CalculatorService
Рекомендуемая структура проекта
Для каждого модуля своя папка. Модуль может состоять из мелких под модулей. Тогда для них создаются папки внутри папки основного модуля. Рассматривайте каждый модуль как отдельное мини приложение которое решает какую-то свою определенную задачу.
Пример: Игра змейка
Для простоты просмотра пометил весь код в один файл.
github.com/VictoremWinbringer/SnakeGameWithOnionAkaCleanArchitecture
Литература
Domain Driven Design – simplifying the complicated
Заблуждения Clean Architecture
UPD
В комментариях пожаловались что картинка у меня кривая поэтому добавил еще одну.
Тут замечание: Gateway == Repository
комментарии (6)