IoC, DI, WTF?

10 сент. 2010 г. | | |

Давайте разберемся с этими загадочными абревиатурами и разницей между ними.

IoC (Inversion of Control) -
инверсия управления, один из принципов S.O.L.I.D., известна так же как Принцип обращения зависимостей (Dependency Inversion Principle, DIP). IoC - очень полезная техника, которая уменьшает связанность и придает гибкость разрабатываемому ПО. Принцип инверсии управления звучит так [wikipedia]:

Модули верхних уровней не должны зависеть от модулей нижних уровней. Оба типа модулей должны зависеть от абстракций. Абстракции не должны зависеть от деталей. Детали должны зависеть от абстракций.
В своей статье Inversion of Control Containers and the Dependency Injection pattern Мартин Фаулер вводит понятие Dependency Injection (Dependency Injection) - внедрение зависимости - как разновидность IoC. Всего он выделяет три типа DI в зависимости от того, через что осуществляется DI:
1) Interface injection
2) Setter injection (пример)
3) Constructor injection (пример)

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

class TxtDocument
{
private string Path;
public TxtDocument(string path){...}
public void Open() {...}
public Stream GetContent() {...}
public void Save(Stream stream) {...}
public void Close(){...}
}
class DocumentManager
{
private TxtDocument document;
public DocumentManager(string path)
{
document = new TxtDocument(path);
}
public Steam GetDocument()
{
document.Open();
Stream stream = document.GetContent();
document.Close();
}
public void SaveDocument(Stream stream)
{
document.Open();
document.Save(steam);
document.Close();
}
}
....
DocumentManager dm = new DocumentManager(@"C:\test.txt");
Stream stream = dm.GetContent();
...
dm.Save(stream);
....

UML-диаграмма:
Что получилось: жесткая зависимость класса DocumentManager от класса TxtDocument. А теперь представьте, что нам понадобилось работать еще и с rtf, doc, pdf, etc. - документами. Что делать? Срочно, срочно применять IoC (DI: Interface injection)! Для этого введем интерфейс IDocument, который будут реализовывать все классы документов.

interface IDocument
{
void Open() {...}
Stream GetContent() {...}
void Save(Stream stream) {...}
void Close(){...}
}
class TxtDocument : IDocument { .... }
class RtfDocument : IDocument { ... }
class DocDocument : IDocument { ... }
class PdfDocument : IDocument { ... }

Класс DocumentManager изменится следующим образом:

class DocumentManager
{
private IDocument document;
public DocumentManager(IDocument _document)
{
document = _document;
}
public Steam GetDocument()
{
document.Open();
Stream stream = document.GetContent();
document.Close();
}
public void SaveDocument(Stream stream)
{
document.Open();
document.Save(steam);
document.Close();
}
}
....
DocumentManager dm = new DocumentManager(new RtfDocument(@"C:\test.rtf"));
Stream stream = dm.GetContent();
...

UML-диаграмма результата:
В результате применения инверсии управления мы получили гибкое решение, которое с легкостью позволяет нам добавлять классы для работы с новыми форматами файлов.

Для автоматизации инверсии управления существуют IoC-контейнеры. Наиболее популярные для .Net :
Unity Application Block 2.0
Spring.NET
Structuremap
CastleProject
Seasar
Winter.NET
Применение IoC-контейнера на примере рассмотрим в следующей заметке.

0 коммент.:

Отправить комментарий