Что такое МОК? Нужны некоторые практические примеры кода для иллюстрации
Может ли кто-нибудь привести меня к некоторым основным учебникам по МОК? (предпочтительно .net/С#).
Мне нужны руки, чтобы обернуть вокруг себя голову:)
Является ли IOC похожим на DDD? или тестовый дизайн?
Ответы
Ответ 1
IOC, или инверсия управления, в большинстве приложений инвертирует маршрут через код из пользовательского интерфейса в базу данных. Это не полный ответ, но это один из самых простых способов понять вашу концепцию.
Если вы хотите изучить IOC, войдите в TDD, так как вы сможете быстрее настроить настройки тестов после того, как вы инвертируете.
Пример:
Типичный поток большинства приложений .NET, которые я видел, выглядит примерно так:
UserCollection col = BusinessLayer.Class.GetLoggedInUsers();
//Business logic
return col;
тогда бизнес выглядит следующим образом:
UserTable table = DataLayer.Class.GetLoggedInUsers();
return table;
и т.д.. Это все псевдокод. Чтобы использовать IOC в этом примере, вы добавляете интерфейс для класса слоя данных, например IUserRepository. Вы можете использовать дженерики, и я бы рекомендовал под капотом.
Затем вы можете сделать что-то вроде этого:
IUserRepository repository = SetUpRepository();
UserCollection col = BusinessLayer.Class.GetUsers(repository);
Почему это важно? Для тестирования вы можете создать ложный репозиторий и подать его в бизнес-класс. Макет содержит данные, которые всегда одни и те же, что означает, что вы выполняете свой код, а не тестируете от конца до конца.
Если вы хотите С#, вот базовый пример на weblogs.asp.net:
Ответ 2
Прочитайте этот отличный article от Мартина Фаулера.
Кроме того, посмотрите статью в википедии.
Инъекция зависимостей является наиболее известным примером инверсии управления, которая коротким превращает ваш код из этого:
public class FileReader { }
public class Application {
// inflexible concrete dependency
private FileReader fileReader = new FileReader();
}
To:
public interface Reader {}
public class FileReader implements Reader {}
public class Application {
// flexible abstract dependency injected in
private Reader reader;
public Application(Reader reader) { // constructor injection
this.reader = reader;
}
public void setReader(Reader reader) { // setter injection
this.reader = reader;
}
}
Ответ 3
Чтобы говорить на жаргоне, инверсия управления - это шаблон, который поддерживает, среди прочего, принцип единой ответственности.
Чтобы понять, почему все это полезно, вам нужно какое-то изложение, так что несите меня.
Единственная ответственность в основном означает, что ваш класс должен быть как можно более независимым от других частей системы, чтобы минимизировать влияние изменения одной части на другую. (Вы также можете связать это с тем фактом, что изменение реализации не должно приводить к повторной компиляции всех файлов в ваших проектах, как это бывает при изменении файлов .h в проекте C/С++).
Побочным эффектом является то, что вы получаете множество мелких предметов, которые делают только одно, но очень хорошо (в идеальном мире)
Но в большинстве случаев для выполнения своей работы один объект должен разговаривать с другим объектом: это зависит от них.
Первая часть смягчения, которая заключается в том, чтобы отделить реализацию от интерфейсов. Это означает полагаться на интерфейсы (или чисто абстрактные классы, в зависимости от выбранного вами языка), так что один объект не привязан к конкретной реализации другого.
Итак, чтобы использовать канонический пример, в бизнес-слое вам нужно выполнить функцию, которая нуждается в доступе к
- Уровень данных для извлечения объектов
- Некоторая другая услуга
- регистратор для регистрации информации и/или ошибок
В свою очередь, у каждой службы или зависимости есть свои зависимости, о которых ваш класс должен знать, даже если они не используют их.
В зависимости от количества ссылок, настройка объекта может быстро выйти из рук. Теперь умножьте это на количество классов, которые вам нужно написать, и вы получите беспорядок.
Использование контейнера IOC в основном помогает вам избавиться от этого беспорядка.
Когда вам нужен объект, вы не "обновляете его". Вместо этого вы запрашиваете контейнер IOC для его получения.
Контейнер отвечает за доставку функционального объекта, готового к использованию, независимо от его зависимостей.
Это означает, что вам класс не нужно знать о зависимостях классов, на которых он опирается, что сокращает путаницу.
Кроме того, ему не нужно знать, какой фактический класс реализует сервисы, на которые он опирается, а это означает, что
- Реализация службы может быть определена в другом проекте (dll или что-то еще), поэтому его изменение никогда не повлияет на ваш класс
- Реализация может отличаться в зависимости от контекста (подумайте об изменении базы данных или даже перейдете на веб-службу для извлечения информации в зависимости от конфигурации или даже текущего состояния приложения).
Чтобы попытаться ответить на другие ваши вопросы, МОК - это образец. TDD и DDD - это методологии проектирования, поэтому нельзя приравнять другую.
Но IOC - бесценный инструмент для поддержки TDD или DDD.
Я знаю, что суп с акронимом и частичные образцы, которые вы можете найти, не так-то просто. Лучший совет, который я могу вам дать, - попробовать немного небольших проектов на стороне, прототипы, которые вы будете канавы, просто чтобы разобраться с этими вещами. Нелегкий способ пойти, если вы смотрите на это для работы, но абсолютно того стоит, если только с личной точки зрения.
Надеюсь, что это поможет.
Ответ 4
Нет, IoC не является DDD или TDD.
Мартин Фаулер article - хорошее введение.
Ответ 5
Для вашего вопроса о том, что такое IOC, Wikipedia имеет довольно обширное объяснение.
Что касается учебников или примеров этот учебник охватывает его довольно хорошо и имеет много примеров кода.
Ответ 6
Если вы понимаете DIP (принцип инверсии зависимостей), IOC - торт. Я предлагаю изучить объектно-ориентированные принципы, прежде чем вы узнаете шаблоны. Основные принципы могут быть сложены как legos для выполнения любого шаблона. Брэндон Джойс
Ответ 7
Инверсия управления - это абстракция логической структуры. Одним из подходов (часто используемым синонимом с IoC) является Dependency Injection, который абстрагирует ссылки между объектами. Когда объекты освобождаются от деталей реализации приложения, например, какой класс реализует эту услугу, они могут сосредоточиться на своих основных функциях.
Например, скажем, у вас есть класс, которому необходимо сопоставить объекты Foo
с объектами Bar
. Вы можете написать это:
public class FooMapper
{
public Bar Map(Foo foo)
{
// ...
}
}
и используйте его следующим образом:
public class NeedsToMapFoos
{
public void MapSomeFoos()
{
var fooMapper = new FooMapper();
// ...
}
}
Хотя он действителен, он также является жестким. NeedsToMapFoos
заботится только о том, что происходит отображение, а не в том, что оно происходит определенным образом.
Мы можем представить концепцию "operation sans implementation" с интерфейсом:
public interface IFooMapper
{
Bar Map(Foo foo);
}
и объявить зависимость от этой операции:
public class NeedsToMapFoos
{
private readonly IFooMapper _fooMapper;
public NeedsToMapFoos(IFooMapper fooMapper)
{
_fooMapper = fooMapper;
}
public void MapSomeFoos()
{
// ...use _fooMapper...
}
}
Теперь NeedsToMapFoos
имеет меньше знаний, что означает, что он менее сложный. Вместо того, чтобы выполнять административные обязанности, он может сосредоточиться на бизнес-деле.
Хорошо подобранные объекты, подобные этому, также более адаптируемы. Подобно тому, как алмазы жесткие, а глина податлива, внутренняя структура определяет реакцию на изменение.
Наконец, логика, написанная в этом стиле, также является гибкой. Скажем, FooMapper.Map
является дорогостоящей операцией и должен быть кэширован. Вы можете использовать шаблон декоратора, чтобы обернуть существующую реализацию и легко передать ее в NeedsToMapFoos
:
public class CachingFooMapper : IFooMapper
{
private readonly IFooMapper _innerMapper;
private readonly IDictionary<Foo, Bar> _cache;
public CachingFooMapper(IFooMapper innerMapper)
{
_innerMapper = innerMapper;
}
public Bar Map(Foo foo)
{
// Read bar from _cache. If not there, read from inner mapper and add to _cache.
}
}
// Usage
new NeedsToMapFoos(new CachingFooMapper(new FooMapper()));