Противоречит ли луковая архитектура IoC

Джеффри Палермо был пионером луковой архитектуры, и я нашел хороший подход.

http://www.headspring.com/jeffrey/onion-architecture-part-4-after-four-years/

Однако его утверждение «Внутренние уровни определяют интерфейсы. Внешние уровни реализуют интерфейсы» кажется противоречащим IoC, если я правильно понимаю, в котором говорится, что потребитель определяет интерфейс, а поставщики реализуют его, т.е. контроль лежит на потребителе, а не на провайдере.

Этот принцип имеет для меня смысл, поскольку, представьте, что вы пишете пользовательский интерфейс, этот принцип означает, что вы можете продолжить создание своего пользовательского интерфейса, ничего не зная о сервисах, которые вы собираетесь вызывать, поскольку вы отвечаете за определение интерфейса, который предоставляет все функциональность, которая вам понадобится.

Таким образом, заявление Джеффриса кажется противоречивым и сбивает меня с толку относительно того, где разместить контракт (определения интерфейсов), потому что, похоже, оно подразумевает следующее: Уровень домена MyEntity IMyService Service MyEntityService: IMyService

Поскольку под доменом нет слоя, куда мне поместить IMyEntity. Также это означает, что я не могу создать проект презентации, пока домен не существует и не определил IMyService.

Как я заметил, где мне разместить IMyEntityRepository и MyEntityRepository? Поскольку сервис полагается на IMyEntityRepository, а MyEntityRepository полагается на IMyEntity


person ricardo    schedule 28.02.2013    source источник


Ответы (4)


Итак, с чего начать? :-)

Начнем с реальной роли МОК. Согласно Википедии,

Инверсия управления - это метод программирования, в котором связывание объектов связывается во время выполнения ассемблерным объектом и обычно не известно во время компиляции.

В вашем случае ваш пользовательский интерфейс будет управлять интерфейсами сервисов, не зная, какая реализация сервиса будет привязана во время выполнения. Потребитель не должен определять эти сервисные интерфейсы; они будут определены в ядре приложения вашей архитектуры Onion, но мы увидим это позже.

«Внутренние уровни определяют интерфейсы. Внешние уровни реализуют интерфейсы», именно так разработана луковая архитектура, но не забывайте, что самый внешний уровень - это IOC! IOC должен связать интерфейсы с правильными реализациями во время выполнения!

Вы правы, говоря, что ваш пользовательский интерфейс не будет работать без наличия хотя бы одной реализации для интерфейсов, которыми вы будете манипулировать. Но в этом случае, если по какой-либо причине вам нужно сначала создать свой пользовательский интерфейс, подумайте об использовании фреймворка для фиксации!

Ваш последний вопрос касается того, где вам нужно разместить классы IMyEntityRepository и MyEntityRepository. Что ж, это простая часть ;-) IMyEntityRepository определенно нужно разместить в ядре вашего приложения. Все ваши сущности, сервисные интерфейсы, интерфейсы репозитория и любые интерфейсы должны быть в одном месте. Реализация MyEntityRepository должна быть размещена где-то на уровне вашей инфраструктуры, поскольку его роль будет в основном заключаться в получении данных из БД.

Надеюсь, это поможет!

person MaxSC    schedule 01.03.2013
comment
Я считаю, что цитата Wiki - это скорее заявление о последствиях IoC и более подходящее определение DI. Насколько я понимаю, «инверсия управления» означает инверсию управления, наложенного на потребителя услуги, так, чтобы потребителю не приходилось приспосабливать услугу, а наоборот. - person ricardo; 06.03.2013
comment
Внедрение зависимости обеспечивает инверсию управления. DI - это всего лишь один из методов реализации IOC (два других метода реализации IOC - это использование фабрик или локатора сервисов). - person MaxSC; 06.03.2013

Я работал с Джеффри много лет, и я бы сказал, что IoC является неотъемлемой частью того, что делает возможной архитектуру Onion. Интерфейсы для внешних зависимостей определены в проектах с небольшим количеством (если они есть) зависимостями (другими словами, проекты в «центре» луковицы). Классы, реализующие те интерфейсы, которые зависят от внешних зависимостей, расположены в проектах на краю / на поверхности луковицы. Таким образом, контейнеры IoC необходимы для «подключения» реализаций классов на краю луковицы к интерфейсам в ядре луковицы во время выполнения.

person Kevin Hurwitz    schedule 01.03.2013

Мы реализовали Onion в моем проекте, и концептуально он довольно прост.

  1. Создайте проект, который содержит только интерфейсы и POCO, на данный момент мы назовем этот Контракт.
  2. Создайте один или несколько проектов, которые содержат реализации ваших интерфейсов и все ваши сторонние вещи, такие как сопоставления NHibernate, мы назовем эти реализации.
  3. Добавьте прямую ссылку на контракт из проектов, которым необходимо использовать эту функцию, но не добавляйте ссылку на реализацию из этих проектов.
  4. В вашем составном корне (точка входа в приложение) проекты делают две вещи (1) как часть сборки, копируют последнюю версию реализации в настроенное место (мы используем AppSettings для конфигурации, но здесь есть много вариантов) (2) пусть ваш контейнер просканирует настроенное место для вашей реализации Dll (-ов)

Этот подход позволяет вам полагаться только на контракт, и идея состоит в том, что вы можете переключить реализацию, поэтому, если вы хотите перейти на Entity Framework или что-то еще в будущем, вам нужно только повторно реализовать реализацию, используя эту структуру.

Мы также копируем библиотеки DLL NHibernate в настроенное место сканирования, и это позволяет нам сделать архитектуру защищенной, так что трудно не следовать ей, потому что NHibernate доступен только там, где он должен использоваться.

person Ryan Vice    schedule 01.03.2013

Интерфейсы в луковичной архитектуре - это те, от которых уровень зависит (т. Е. потребляет), чья реализация действительно обеспечивается внешним уровнем.

В частности, сама архитектура не говорит, что вам нужно абстрагироваться от бизнес-логики за интерфейсами (что, вероятно, вам все равно следует сделать в отношении принцип инверсии зависимостей, но это уже другая история). В нем говорится, что зависимости уровня должны быть смоделированы как интерфейсы, чтобы реализации могли быть предоставлены внешним уровнем.

Лучшим примером является код инфраструктуры и, в частности, доступ к данным. Ваша бизнес-логика должна загружать и хранить данные, поэтому она определяет интерфейс, который будет потреблять. Внешний уровень предоставит реализацию с использованием NHibernate или EF или чего-то еще.

Фактически, низкоуровневые уровни (от DIP; т. Е. Доступ к данным и другие ресурсы) находятся на самых внешних слоях луковицы, в то время как высокоуровневые уровни ( т.е. бизнес-логика) ближе к центру.

См. Также http://blog.8thlight.com/uncle-bob/2012/08/13/the-clean-architecture.html, который заменяет домен, бизнес-логику и дополнительную бизнес-логику. термины с объектами, вариантами использования и интерфейсными адаптерами, о которых легче рассуждать по IMO. Чем дальше вы уходите от центра, тем точнее вы относитесь к тому, что пользователь видит и использует; чем ближе к центру, тем универсальнее; в центре находятся те вещи, которые являются поперечными по отношению к вашему предприятию, тогда варианты использования, специфичные для вашего приложения, больше не диктуют, как они будут использоваться или в какой среде (какая БД, какой пользовательский интерфейс и т. д.), тогда вы сделаете адаптеры между вашими вариантами использования и своей технической структурой (ASP.NET MVC, WCF, WPF - в сценариях, отличных от веб-сайтов, EF, NHibernate и т. д.)

person Thomas Broyer    schedule 27.04.2013