Skip to content

sunmeat/DIP

Repository files navigation

Dependency Inversion Principle

Dependency Inversion Principle (DIP) – принцип инверсии зависимостей, который говорит, что: Модули верхних уровней не должны зависеть от модулей нижних уровней. Оба типа модулей должны зависеть от абстракций. Абстракции не должны зависеть от деталей. Детали должны зависеть от абстракций. Признаки слишком высокой зависимости архитектуры: Жёсткость. Меняем в одном месте – вынуждены менять в куче других мест. Хрупкость. Меняем в одном месте – начинаются ошибки в куче других мест. Неподвижность. Сложно вынести код в другой проект. Причина этих проблем в том, что между классами возникает слишком много жёстко прописанных зависимостей.

Инверсия зависимостей предлагает избавиться от жёстко прописанных зависимостей между классами, инвертировав их в зависимости от абстракций. Суть здесь в инверсии сильных зависимостей от реализаций в слабые зависимости от абстракций.

Чуть упрощённая, но действенная интерпретация принципа DIP выражается эвристическим правилом «зависеть надо от абстракции». Это значит, что не должно быть зависимостей от конкретных классов. Вместо этого типы указателей на зависимости должны быть интерфейсами или абстрактными классами. Главным плюсом инвертирования зависимостей является инвертирование владения: не мы владеем объектом – не мы за него отвечаем. Мы на этот объект просто указываем. А значит, зависимость от него (связь с ним) – слабая, как того и требует условие «низкая связанность».

Паттерны реализации принципа инверсии зависимости, в данном случае паттерны проектирования: Factory Method Service Locator Dependency Injection Паттерн Dependency Injection (внедрение зависимости) – не просто инвертирует сильные зависимости от реализаций в слабые зависимости от абстракций, но и выносит их из класса, предлагая внедрять их в класс извне. Классический вариант внедрения зависимости в наш класс – через конструктор. В результате, мы заменяем композицию агрегацией и перекладываем часть проблем с текущего класса куда-то выше. Именно паттерн Dependency Injection является реализацией условия «Слабая внешняя связанность». Он как раз и занимается ослаблением связей между классами. Программируйте на основе абстракций (интерфейс, абстрактный класс и т.п.), а не реализаций.

===============================================================================

задания для практики:

  1. Создайте класс для отправки электронной почты. Напишите несколько классов, которые могут использовать этот класс, например, класс для отправки уведомлений пользователю и класс для отправки отчетов администратору. Используйте принцип Dependency Inversion, чтобы обеспечить возможность замены класса для отправки электронной почты на другой класс без изменения кода этих двух классов.

  2. Создайте интерфейс для работы с базой данных, который объявляет методы для выполнения CRUD-операций. Создайте несколько реализаций этого интерфейса, например, реализацию для работы с MySQL и реализацию для работы с MongoDB. Создайте класс, который будет использовать этот интерфейс, например, класс для работы со статьями на сайте. Используйте принцип Dependency Inversion, чтобы этот класс мог использовать любую из реализаций интерфейса, без изменения его кода.

  3. Для реализации принципа Dependency Inversion Principle мы можем использовать класс Person и класс Food, где класс Person будет зависеть от абстракции класса Food, а не от конкретных реализаций.

Давайте представим, что у нас есть класс Person, который представляет человека, и класс Food, который представляет еду. Класс Food будет абстрактным классом, который будет иметь несколько наследников, таких как классы Breakfast, Lunch и Dinner, представляющие различные приемы пищи.

Класс Person будет иметь метод eat, который принимает объект типа Food в качестве аргумента. Этот метод будет вызывать метод prepare, который будет реализован в каждом конкретном наследнике класса Food.

Например, для завтрака мы можем создать конкретный класс Breakfast, который будет иметь свою реализацию метода prepare. В зависимости от выбранного завтрака, метод prepare будет подготавливать соответствующее блюдо, такое как яйца, омлет или кашу. Таким образом, при реализации принципа Dependency Inversion Principle мы избегаем жестких зависимостей между классами Person и Food, что позволяет легко добавлять новые типы еды, не меняя код класса Person. Также мы можем легко заменять конкретные реализации наследников класса Food, не затрагивая код класса Person.