Может ли внедрение зависимости предотвратить циклическую зависимость? - PullRequest
3 голосов
/ 13 января 2010

Проект № 1 имеет несколько интерфейсов и классов, которые ссылаются на проект № 2.

Теперь я хочу использовать реализацию проекта № 2 в проекте № 1, но vs.net жалуется на циклическую зависимость.

Если бы мне пришлось использовать внедрение зависимости в Проекте № 1 и связать его с реализацией в Проекте № 2 (поскольку он соответствует контракту интерфейса), будет ли это работать или я все равно получу сообщение об ошибке циклической зависимости во время выполнения?

Ответы [ 3 ]

15 голосов
/ 13 января 2010

Вы, вероятно, могли бы решить эту проблему с помощью DI, но вы не должны .

Если я правильно понимаю, у вас есть что-то вроде этого:

  + Assembly A           + Assembly B
  |                      |
  +-- Interface IFoo     +-- Class ConcreteFoo : IFoo
  |                                   ^
  +-- Class MyClass -->------->-------|

Другими словами, вы пытаетесь получить MyClass для ссылки на ConcreteFoo, но не можете, потому что сборка B, в которой находится ConcreteFoo, уже зависит от IFoo в A .

Это ошибка проектирования. Если вы объявляете интерфейс IFoo в сборке A, но без конкретных реализаций, тогда любые другие интерфейсы / классы в сборке A должны только ссылка IFoo, никогда конкретный класс, который его реализует.

Существует три способа устранения круговой зависимости:

  1. Сделать MyClass зависимым от IFoo вместо ConcreteFoo. Это, вероятно, лучший вариант, если вы можете это сделать. Если проблема заключается в том, что вам нужен физический экземпляр IFoo для использования в MyClass и вы не знаете, где его получить, тогда пусть в конструкторе будет IFoo - пусть тот, кто использует фигуру MyClass что IFoo использовать.

  2. Переместите интерфейсы в их собственную сборку. Это все еще достаточно хорошая практика. Ваш дизайн будет выглядеть так:

      + Assembly App       + Assembly Interfaces      + Assembly Concrete
      |                    |                          |
      |                    +-- Interface IFoo         |
      |                    |                  \       |
      +-- Class MyClass    |                   \------+-- Class ConcreteFoo
      |                    |                          |           ^
      +---- Member Foo ->--------------------->-------------------|
    
  3. Переместить MyClass в свою сборку. По сути, ваше дерево зависимостей будет выглядеть так же, как в # 2 выше, но если сборка A намного меньше, чем B, тогда это потребует меньше усилий.

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

8 голосов
/ 13 января 2010

Вы можете часто разрешать проблемы циклических зависимостей с помощью Dependency Injection (DI), используя Abstract Factory. См. здесь для примера .

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

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

1 голос
/ 13 января 2010

Пока вы используете только классы и интерфейсы из Проекта 1 в коде Проекта 1, у вас все будет хорошо. (Я предполагаю, что конфигурация для внедрения зависимостей выполняется за пределами кодовой базы проекта 1.)

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

...