Внедрение зависимостей, упомянутое в руководстве C ++ Google Mock - PullRequest
3 голосов
/ 30 декабря 2011

Что они имеют в виду под инъекцией зависимостей (инверсия контроля) в этом контексте ( Google Mock ):

Давайте посмотрим на пример. Предположим, вы разрабатываете графику Программа, которая использует LOGO-подобный API для рисования. Как бы вы проверить что он делает правильно? Ну, вы можете запустить его и сравнить экран с золотым снимком экрана, но давайте признаем это: тесты как это дорого для запуска и хрупкий (Что если вы просто обновились до новая блестящая видеокарта с улучшенным сглаживанием? Вдруг ты должны обновить все ваши золотые изображения.). Было бы слишком больно, если все ваши тесты такие. К счастью, вы узнали о Внедрение зависимости и знать, что нужно делать: вместо того, чтобы иметь Ваше приложение напрямую обращается к API рисования, оборачивая API в интерфейс (скажем, черепаха) и код для этого интерфейса :

class Turtle {
  ...
  virtual ~Turtle() {}
  virtual void PenUp() = 0;
  virtual void PenDown() = 0;
  virtual void Forward(int distance) = 0;
  virtual void Turn(int degrees) = 0;
  virtual void GoTo(int x, int y) = 0;
  virtual int GetX() const = 0;
  virtual int GetY() const = 0;
};

Какое отношение это имеет к DI при добавлении другого слоя между кодом приложения и API рисования классом ? Во многих Java-примерах о Dependency Injection обычно объект не должен создаваться конкретно внутри класса. Скорее, он должен быть создан в другом месте, чтобы отделить связь реализации между двумя объектами. Например (источник из codeproject ):

enter image description here

Решение:

enter image description here

Когда я искал ответы о DI в Stackoverflow, обычно его спрашивают в контексте Java. Некоторые примеры использовали графический интерфейс Java. Обычно примеры настолько просты и очевидны, что я не видел их значения, за исключением того, что у меня был лучший дизайн с меньшим количеством связей. Тем не менее, что я хочу узнать, это смысл этого. Как определено в wiki , инверсия управления (IoC) означает, что вы инвертируете поток управления кодом. Итак, как это относится к делу Google? Как реальный поток перевернут по сравнению с процедурным стилем? Я думал, что код выполняется последовательно строка за строкой сверху вниз, а не снизу вверх?

Ответы [ 4 ]

3 голосов
/ 30 декабря 2011

В Википедии есть хорошие определения:

  1. http://en.wikipedia.org/wiki/Inversion_of_control
  2. http://en.wikipedia.org/wiki/Dependency_injection

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

В отношении инверсии контроля Википедия упоминает такие вещи, как шаблон Фабрики.

В нем также упоминается внедрение метода setter (изменение реализации интерфейса с помощью функции setter), внедрение конструкции (настройка реализации интерфейса из конструктора) или внедрение интерфейса (запрос реализации интерфейса из другого интерфейса) и отмечает, что это типы зависимостей. Инъекции.

Это то, что происходит здесь - программа может изменить API рисования программы черепахи (Dependency Injection), используя метод установки (Inversion of Control).

Это позволяет вам иметь тестовый класс, подобный этому:

struct DrawingTester : public DrawingInterface
{
    void move_to(long x, long y) { printf("moveto %d %d\n", x, y); }
    void line_to(long x, long y) { printf("lineto %d %d\n", x, y); }
};

и запустить его через тестовую программу:

int main(int argc, char **argv) {
    DrawingTester drawing;
    Turtle t;
    t.setDrawingApi(&drawing);
    t.runProgramFromFile(argv[0]);
    return 0;
}

После этого вы можете получить программы тестирования черепахи / логотипа с ожидаемым выводом из DrawingTester. Например:

# test1.logo

MOVE 5, 7

# test1.calls

moveto 5 7

и проведите его через набор тестов (например, https://github.com/rhdunn/cainteoir-engine/blob/master/tests/harness.py и https://github.com/rhdunn/cainteoir-engine/blob/master/tests/metadata.py).

3 голосов
/ 30 декабря 2011

DI означает здесь, что ваша программа не имеет жестко закодированной зависимости от API-интерфейса, подобного LOGO, но эта зависимость «внедряется» во время выполнения через интерфейс. Таким образом, можно заменить API на Mock API для модульного тестирования.

«Инверсия управления» означает здесь: если в вашей программе есть функция, требующая чего-то вроде «объекта графического контекста» в LOGO-подобном API, она не должна создавать экземпляр этого объекта сама. Вместо этого он должен получить объект контекста, заданный как параметр (типизированный для интерфейса "Turtle"), и создание объекта может быть выполнено, например, с помощью инфраструктуры IoC.

Это будет работать так же, как вы показали в приведенном выше примере с "адресом клиента", замените clsAddress на clsGraphicsContext.

2 голосов
/ 30 декабря 2011

Инверсия в «Inversion of Control» - это не инверсия в порядке выполнения кода, а при создании объекта.В архитектуре, которая не использует «Внедрение зависимостей», объекты сами создают свои зависимости.Напротив, при использовании DI объект будет получать свою зависимость извне и будет использовать интерфейс (абстрактный класс в C ++), чтобы получить независимость от реализации.

В примере LOGO, используя интерфейс иУстановщик вместо того, чтобы создавать обертку API напрямую, вы позволяете коду, который вызывает вас, предоставлять свою реализацию интерфейса.Таким образом, проще протестировать свой код (предоставив имитирующую реализацию, которая записывает все выполненные вызовы) или использовать другую реализацию.

1 голос
/ 30 декабря 2011

Мне кажется, что вы как бы "приравниваете" внедрение зависимости и инверсию управления.

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

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...