Как использовать фабричный метод при написании кода на Python |
||||||||||||||||||
МЕНЮ Искусственный интеллект Поиск Регистрация на сайте Помощь проекту ТЕМЫ Новости ИИ Искусственный интеллект Разработка ИИГолосовой помощник Городские сумасшедшие ИИ в медицине ИИ проекты Искусственные нейросети Слежка за людьми Угроза ИИ ИИ теория Внедрение ИИКомпьютерные науки Машинное обуч. (Ошибки) Машинное обучение Машинный перевод Реализация ИИ Реализация нейросетей Создание беспилотных авто Трезво про ИИ Философия ИИ Big data Работа разума и сознаниеМодель мозгаРобототехника, БПЛАТрансгуманизмОбработка текстаТеория эволюцииДополненная реальностьЖелезоКиберугрозыНаучный мирИТ индустрияРазработка ПОТеория информацииМатематикаЦифровая экономика
Генетические алгоритмы Капсульные нейросети Основы нейронных сетей Распознавание лиц Распознавание образов Распознавание речи Техническое зрение Чат-боты Авторизация |
2019-07-17 09:00 Часто сталкиваетесь с условными конструкциями, с которыми трудно работать? Рассказываем про такой шаблон проектирования, как фабричный метод. Фабричный метод ? это шаблон проектирования, используемый для создания общего интерфейса. Например, приложению требуется объект с определенным интерфейсом для выполнения задач. Реализация интерфейса определяется некоторым параметром. Вместо использования сложной структуры из условий Представьте себе приложение, которому необходимо преобразовать объект Song в String. Преобразование объекта называется сериализацией. Эти требования часто реализованы в одной функции или методе, которые содержат всю логику:
В приведенном выше примере есть базовый класс Song для представления песни и класс SongSerializer, который преобразовывает объект Song в его строковое представление в соответствии со значением параметра format. Метод .serialize() поддерживает два разных формата: JSON и XML. Любой другой указанный формат не поддерживается, поэтому возникает исключение ValueError. Воспользуемся интерактивной оболочкой Python, чтобы увидеть, как работает код:
Создаются объект Song и serializer, затем Song преобразуется в строковое представление с помощью метода .serialize(). Метод принимает в качестве параметров объект Song и строковое значение. Последний вызов использует YAML в качестве формата, который не поддерживает serializer, поэтому возникает исключение ValueError. Это короткий и упрощенный пример, но в нем есть три логических ветви исполнения, которые зависят от значения параметра format и усложняют код. Проблемы сложного кода с условиями Пример выше раскрывает проблемы, с которыми вы столкнетесь в сложном логическом коде. Структуры Код сложен еще и потому, что выполняет много действий. Согласно принципу единственной ответственности, модуль, класс и даже метод должны выполнять одну функцию в коде и иметь причину изменения своих состояний. Метод .serialize() в SongSerializer может изменяться по многим причинам. Такое поведение способно привести к появлению проблем. Давайте рассмотрим все возможные ситуации, когда придется вносить изменения в реализацию:
В идеале, любое изменение вносится без использования метода .serialize(). В поисках общего интерфейса Если вы видите сложный код с условиями, определите общие цели каждого логического ответвления. Код, в котором используются Нужно найти общий интерфейс, который можно использовать для замены каждой ветви. В приведенном выше примере требуется такой интерфейс, который принимает объект Song и возвращает строку. Когда есть общий интерфейс, мы предоставляем отдельные реализации для каждого способа. В примере выше мы сначала осуществляем сериализацию в JSON и XML, а затем предоставляем отдельный компонент, который решает, какую реализацию использовать на основе указанного формата. Этот компонент оценивает значение format и возвращает конкретную реализацию, определенную его значением. В следующих разделах вы узнаете, как вносить изменения в существующий код без изменения поведения ? проводить рефакторинг кода. Рефакторинг кода в желаемый интерфейс Желаемый интерфейс ? это объект или функция, которая принимает объект Song и возвращает строковое представление. Первым шагом является рефакторинг одного из логических ответвлений в этот интерфейс. Добавляем новый метод ._serialize_to_json() и перемещаем в него код сериализации JSON. Затем изменяем клиент для вызова, вместо реализации в теле оператора
После внесения этих изменений вы сможете убедиться, что поведение осталось прежним. Затем делаем то же самое для XML, представляя новый метод ._serialize_to_xml(), перемещая реализацию в него и изменяя ветку В следующем примере показан переработанный код:
Новая версия воспринимается проще, но ее можно улучшать дальше с помощью базовой реализации фабричного метода. Базовая реализация фабричного метода Главная идея фабричного метода заключается в том, чтобы предоставить отдельному компоненту ответственность за решение, какую реализацию следует использовать на основе определенного параметра. Этим параметром в нашем примере является format. Чтобы завершить реализацию фабричного метода, вы добавляете новый метод ._get_serializer(), который принимает желаемый формат. Он оценивает значение format и возвращает соответствующую функцию сериализации:
Теперь можно изменить метод .serialize() в SongSerializer для использования ._get_serializer(), чтобы завершить реализацию фабричного метода. Вот так:
Окончательная реализация показывает различные компоненты фабричного метода. Это ? клиентский компонент шаблона. Определенный интерфейс называется компонентом-продуктом, в нашем случае продукт ? это функция, которая принимает Song и возвращает строковое представление. Методы ._serialize_to_json() и ._serialize_to_xml() являются конкретными реализациями продукта. Наконец, метод ._get_serializer() является компонентом-создателем. Создатель решает, какую реализацию использовать. Поскольку вы начали с уже существующего кода, все компоненты фабричного метода являются частями класса SongSerializer. Обычно это не так, как видно, ни один из добавленных методов не использует параметр self. Это признак того, что они не должны быть методами класса SongSerializer, а могут стать внешними функциями:
Механика фабричного метода всегда одинакова. Клиент зависит от конкретной реализации интерфейса. Он запрашивает реализацию от компонента-создателя, используя какой-то идентификатор. Создатель возвращает конкретную реализацию в соответствии со значением параметра клиенту, а клиент использует предоставленный объект для выполнения своей задачи. Вы можете выполнить тот же набор инструкций в интерактивном интерпретаторе Python, чтобы убедиться, что поведение приложения не изменилось:
Вы создаете Song и serializer и используете serializer для преобразования Song в строковое представление с указанием формата. Поскольку YAML не является поддерживаемым форматом, появляется ValueError. Фабричный метод должен использоваться в любой ситуации, когда приложение (клиент) зависит от интерфейса (продукта), и существует несколько реализаций этого интерфейса. Вам нужно предоставить параметр, который может идентифицировать конкретную реализацию и использовать ее в создателе. Существует широкий спектр похожих задач, поэтому давайте рассмотрим примеры. Замена сложного логического кода: сложные логические структуры Фабричный метод ? хорошая замена, потому что вы можете поместить тело логической ветки в отдельные функции или классы с общим интерфейсом, а создатель может предоставить конкретную реализацию. Построение родственных объектов из внешних данных: представьте себе приложение, которое должно получать информацию о сотрудниках из базы данных. Поддержка нескольких реализаций одной функцией: приложение обработки изображений должно преобразовывать спутниковое изображение из одной системы координат в другую, но существует несколько алгоритмов с различными уровнями точности для выполнения преобразования. Приложение позволяет пользователю выбрать опцию, которая идентифицирует алгоритм. Фабричный метод может обеспечить реализацию алгоритма на основе этой опции. Объединение похожих функций в общем интерфейсе. В соответствии с примером обработки изображений приложение должно применить фильтр. Необходимый фильтр может быть идентифицирован с помощью пользовательского ввода, а фабричный – предоставить реализацию фильтра. Интеграция c внешними службами. Приложение музыкального проигрывателя способно интегрироваться с внешними службами, чтобы пользователи могли выбрать музыкальные источники. Приложение может определить общий интерфейс для музыкального сервиса и использовать фабричный метод для создания правильной интеграции на основе пользовательских предпочтений. Все приведенные ситуации схожи. Они предоставляют средства для определения реализации продукта, поэтому во всех проектах может использоваться фабричный метод. Фабричный метод ? это широко используемый шаблон проектирования, который можно использовать в ситуациях с несколькими реализациями интерфейса. Источник: proglib.io Комментарии: |
|||||||||||||||||