Архитектура лука противоречит IoC
Джеффри Палермо был пионером в создании луковой архитектуры, к которой я нашел хороший подход.
http://www.headspring.com/jeffrey/onion-architecture-part-4-after-four-years/
Однако его утверждение "Внутренние уровни определяют интерфейсы. Внешние уровни реализуют интерфейсы", если мое понимание правильное, противоречит IoC, в котором говорится, что потребитель определяет интерфейс, а поставщики реализуют его, то есть управление принадлежит потребителю, а не поставщику.
Этот принцип имеет смысл для меня, так как, представьте, что вы пишете пользовательский интерфейс, этот принцип означает, что вы можете приступить к созданию пользовательского интерфейса, ничего не зная об услугах, которые вы собираетесь вызывать, поскольку вы отвечаете за определение интерфейса, который предоставляет все функциональность, которая вам понадобится.
Таким образом, заявление Джеффриса кажется противоречивым и сбивает меня с толку насчет того, куда заключать контракт (определения интерфейса), потому что оно, похоже, подразумевает следующее: Сервис домена MyEntity IMyService MyEntityService: IMyService
Поскольку под Доменом нет слоя, куда я помещаю IMyEntity. Также это означает, что я не могу создать презентационный проект, пока домен не существует и не определил IMyService.
Как я заметил, где я могу разместить IMyEntityRepository и MyEntityRepository? Так как сервис полагается на IMyEntityRepository, а MyEntityRepository полагается на IMyEntity
4 ответа
Итак, с чего начать?:-)
Давайте начнем с реальной роли МОК. Согласно Википедии,
Inversion Of Control - это метод программирования, в котором связывание объектов во время выполнения связано с ассемблерным объектом и обычно не известно во время компиляции.
В вашем случае ваш пользовательский интерфейс будет управлять интерфейсами служб, не зная реализацию службы, которая будет связана во время выполнения. Потребителю не нужно определять эти сервисные интерфейсы; они будут определены в ядре приложения вашей архитектуры Onion, но мы увидим это позже.
"Внутренние уровни определяют интерфейсы. Внешние уровни реализуют интерфейсы", так разработана архитектура Onion, но не забывайте, что самый внешний уровень - это IOC! Именно МОК должен связывать интерфейсы с правильными реализациями во время выполнения!
Вы правы, говоря, что ваш пользовательский интерфейс не будет работать без наличия хотя бы одной реализации для интерфейсов, которыми вы будете манипулировать. Но в этом случае, если по какой-либо причине вам необходимо сначала создать свой пользовательский интерфейс, подумайте об использовании фреймворка!
Ваш последний вопрос о том, где вам нужно разместить классы IMyEntityRepository и MyEntityRepository. Ну, это легкая часть;-) IMyEntityRepository определенно должен быть помещен в ядро вашего приложения. Все ваши объекты, сервисные интерфейсы, интерфейсы репозитория и любые другие интерфейсы должны быть в одном месте. Реализация MyEntityRepository должна быть размещена где-то на уровне вашей инфраструктуры, поскольку его роль будет главным образом касаться извлечения данных из БД.
Надеюсь, это поможет!
Я работал с Джеффри много лет, и я бы сказал, что IoC является неотъемлемой частью создания Onion Architecture. Интерфейсы для внешних зависимостей определяются в проектах с небольшими (если таковые имеются) зависимостями (другими словами, проекты в "центре" лука). Классы, которые реализуют те интерфейсы, которые зависят от внешних зависимостей, расположены в проектах на краю / на поверхности лука. Контейнеры IoC, таким образом, необходимы, чтобы "подключить" реализации классов на краю лука к интерфейсам в ядре лука во время выполнения.
Мы внедрили Onion в мой проект, и концептуально он довольно прост.
- Создайте проект, который содержит только интерфейсы и POCO, сейчас мы назовем этот контракт
- Создайте один или несколько проектов, которые содержат реализации ваших интерфейсов и все ваши сторонние вещи, такие как сопоставления NHibernate, мы будем называть этой реализацией
- Добавьте прямую ссылку на контракт из проектов, которым необходимо использовать эту функцию, но не добавьте ссылку на реализацию из этих проектов
- В ваших составных корневых проектах (точка входа в приложение) выполните две вещи (1), как часть сборки, скопируйте последнюю версию реализации в настроенное место (мы используем AppSettings для конфигурации, но здесь есть много вариантов) (2) ваш контейнер сканирует настроенное местоположение для ваших DLL (ов) реализации
Этот подход позволяет вам полагаться только на Contract, и идея заключается в том, что вы можете переключать реализацию, поэтому, если вы хотите перейти к Entity Framework или чему-то еще в будущем, вам нужно только переопределить реализацию, используя эту платформу.
Мы также копируем библиотеки DLL NHibernate в настроенное место сканирования, и это позволяет нам сделать архитектуру защитной, чтобы было трудно не следовать ей, потому что NHibernate доступен только там, где его следует использовать.
Интерфейсы в луковой архитектуре - это те, от которых зависит уровень (то есть потребляет), чья реализация действительно обеспечивается внешним уровнем.
Более конкретно, сама архитектура не говорит о том, что вы должны абстрагировать бизнес-логику от интерфейсов (что вам, вероятно, следует делать в любом случае в отношении принципа инверсии зависимостей, но это уже другая история). Говорят, что зависимости уровня должны быть смоделированы как интерфейсы, чтобы реализации могли быть предоставлены внешним уровнем.
Наилучшим примером является код инфраструктуры и, в частности, доступ к данным. Ваша бизнес-логика должна загружать и хранить данные, поэтому она определяет интерфейс, который она будет использовать. Внешний уровень обеспечит реализацию с использованием NHibernate или EF или чего-либо еще.
На самом деле, низкоуровневые уровни (из DIP; т.е. доступа к данным и других товаров) находятся на внешних слоях лука, а высокоуровневые уровни (т. Е. Бизнес-логика) находятся ближе к центру.
См. Также http://blog.8thlight.com/uncle-bob/2012/08/13/the-clean-architecture.html который заменяет домен, бизнес-логику и другие термины бизнес-логики сущностями, вариантами использования и интерфейсными адаптерами, которые ИМО легче рассуждать. Чем дальше вы идете от центра, тем более конкретно вы видите то, что пользователь видит и использует; чем ближе к центру, тем более общий; в центре находятся те вещи, которые являются поперечными для вашего предприятия, тогда варианты использования, которые являются специфическими для вашего приложения, больше не определяют, как они будут использоваться или в какой среде (какая БД, какой пользовательский интерфейс и т. д.), затем вы создадите адаптеры между вашими сценариями использования и технической инфраструктурой (ASP.NET MVC, WCF, WPF - в сценарии, не связанном с сетью, - EF, NHibernate и т. д.)