Слабосвязанный код Python с внедрением зависимостей
Программное обеспечение должно быть гибким, чтобы реагировать на изменения. Внедрение зависимостей — это метод управления зависимостями между программными компонентами. Это шаблон проектирования, который использует инверсию управления , чтобы обеспечить возможность замены компонентов для тестирования или других целей без изменения какой-либо другой части системы.
Основная идея внедрения зависимостей состоит в том, чтобы передать ответственность за предоставление услуг от функций-конструкторов или прямых методов создания экземпляров другим объектам. Другими словами, объект получает свои зависимости, а не создает их. Таким образом, если мы хотим добавить новые функции, нам не нужно изменять существующий код, а вместо этого передавать в него новые зависимости.
Создание абстракций с интерфейсами
Написание слабосвязанного кода Python с внедрением зависимостей состоит из трех шагов. Первый шаг — определить, какие зависимости нужны коду, второй шаг — создать интерфейсы для каждой зависимости, а третий шаг — передать их зависимому объекту через его конструктор или параметры метода.
Недавно я реализовал функциональность, которая требовала байтового кодировщика и декодера для манипулирования бизнес-данными ( я упростил ее реализацию для удобства чтения ). Я перенес их обязанности на интерфейсы. В Python нет ключевого слова interface, как в Golang, но вы можете воспроизвести функциональность интерфейса с помощью библиотеки ABC .
Ориентируясь на IPacketEncoderинтерфейс, его должен реализовать конкретный класс кодировщика. Первоначальные бизнес-требования требовали, чтобы все типы были закодированы, а строки были дополнены их длиной. К счастью, Python предоставляет библиотеку struct для выполнения большей части тяжелой работы.
Реализация внедрения зависимостей
Функция encode_nameпредставляет собой простую реализацию для создания закодированной полезной нагрузки с указанным именем. Он принимает IPacketEncoderобъект и строку в качестве параметров.
Две ключевые детали реализации — использование IPacketEncoderинтерфейса вместо PaddedPacketEncoderконкретного класса и encoderаргумент, а не инициализация внутри функции. Это внедрение зависимостей. Поскольку IPacketEncoderон передается, его можно легко расширить, изменить или снабдить заглушкой , тем самым сохраняя слабую связанность системы.
Несколько недель спустя появилось новое требование к кодировщику для обработки кодировок с завершающим нулем. К счастью, благодаря существующей реализации его можно легко реализовать.
NullTerminatedPacketEncoderпо существу добавляется NULL_BYTEпосле каждой закодированной строки. Возвращаясь к encode_nameфункции, экземпляр NullTerminatedPacketEncoderявляется допустимым аргументом кодировщика, поскольку NullTerminatedPacketEncoderреализует IPacketEncoderинтерфейс аналогично PaddedPacketEncoder.
Если бы здесь не использовалась инъекция зависимостей, это могло бы привести к сильно связанному коду, который трудно изменить, например:
Если потребуется новый энкодер, encode_nameпридется почти полностью изменить функцию вместе с ее тестами, что продлит сроки поставки. Что еще хуже, это может привести к скрытым побочным эффектам, особенно если исходный разработчик больше недоступен.
В заключение я приведу менее упрощенный пример использования этой техники. SocketServiceотвечает за декодирование кода операции, вызов соответствующего обработчика и возврат результата. Все его типы аргументов являются абстракциями интерфейса, включая его конструктор. CLI отвечает за определение используемого кодировщика, т.е. NullTerminated или Padded, и передачу его экземпляра в SocketServiceкласс.
Поскольку проекты продолжают расти, рекомендуется использовать инфраструктуру внедрения зависимостей для автоматического «внедрения» этих зависимостей, например Dependency Injector .
Надеюсь, это демонстрирует, как писать слабосвязанный код Python с внедрением зависимостей. Многим разработчикам Python не нравится внедрение зависимостей, потому что они считают его не «питоновским», но я бы сказал, что его преимущества не могут быть дискредитированы, особенно когда он присутствует во многих других языках программирования.
Спасибо за прочтение . Если вы хотите связаться со мной, вы можете найти меня на Linkedin или Github .

![В любом случае, что такое связанный список? [Часть 1]](https://post.nghiatu.com/assets/images/m/max/724/1*Xokk6XOjWyIGCBujkJsCzQ.jpeg)



































