Feel Good.

04 февраля 2010

Принцип инверсии зависимости

Что такое зависимость? Задавались ли Вы вопросом, как много зависимостей присутствует в Вашем проекте? Для начала проясним ситуацию и определим понятие зависимость. Представьте ситуацию: есть 2 класса, один(X) из которых использует другой(Y), например делает вызовы методов - это и есть зависимость одного от другого (X от Y).

Для наглядности приведу пример из жизни: у нас есть класс Processor, и класс Сomputer. Сomputer содержит("has a") процессор Processor, который, в свою очередь, имеет некую частоту ClockRate:

class Processor

{

    public int ClockRate

    {

        get

        {

            return 166;

        }

    }

}

 

class Computer

{

    protected Processor _processor;

 

    public Computer()

    {

        _processor = new Processor();

    }

 

    public void PrintDescription()

    {

        Console.Write("Clock rate: {0} Mhz", _processor.ClockRate);

    }

}


Заметили, в нашем примере класс Сomputer жестко зависит от Processor? "Ну и что, в чем же проблема данного кода?" - спросите Вы. А вот они, проблемы:

  1. Конкретный Сomputer зависит от конкретного Processor, в данном случае частотой 166 МГц.
  2. Изменение сигнатуры конструктора Processor, влечет за собою изменение кода конструктора Сomputer.
  3. Нельзя протестировать Сomputer отдельно от Processor, подменив последний ложным для симуляции.
Как же быть в данной ситуации?
Применить паттерн "Принцип инверсии зависимости" (IoC / DI)!
Итак, для начала опишем интерфейс IProcessor, от которого унаследуем наш конкретный процессор:

interface IProcessor

{

    int ClockRate

    {

        get;

    }

}

class Processor : IProcessor

{

    public int ClockRate

    {

        get

        {

            return 166;

        }

    }

}

 

class Computer

{

    protected IProcessor _processor;

 

    public Сomputer(IProcessor processor)

    {

        _processor = processor;

    }

 

    public void PrintDescription()

    {

        Console.Write("Clock rate: {0} Mhz", _processor.ClockRate);

    }

}


Все, готово! Мы разорвали связь между конкретным классом Сomputer и Processor через интерфейс IProcessor. Взгляните: Processor создается отдельно, а затем внедряется через конструктор Сomputer. Да, согласен, каждый раз писать

IProcessor processor = new Processor();

Computer computer = new Computer(processor);


не очень-то и удобно, но для этого и были придуманы различные IoC фреймворки.


Продолжение. Hello, Unity 2.0

4 комментария:

  1. Далеко не первая статья об IoC, которую я прочитал, но первая, благодаря которой допёр, что это, наконец, такое. Жду продолжения.

    ОтветитьУдалить
  2. а где продолжение?)))

    ОтветитьУдалить
  3. Продолжение:
    http://www.handcode.ru/2010/04/hello-unity-20.html

    ОтветитьУдалить
  4. ничего не понял...а чего тут нового то???
    обычное наследование и обычное ООП...

    ОтветитьУдалить