Обратные вызовы в C++ - [13]

Шрифт
Интервал

Отсутствие трансляции контекста. Отсутствие необходимости трансляции контекста упрощает разработку, улучшает прозрачность кода и повышает независимость компонентов. И наоборот, трансляция контекста усложняет код и заставляет инициатор выполнять дополнительные операции для хранения и передачи контекста

Безопасность. Показывает устойчивость системы к потенциальным ошибкам.

Гибкость. Показывает, насколько просто модифицировать код при появлении новых требований.

Полиморфизм. Показывает, поддерживается ли полиморфизм в реализации исполнителя. Поддержка полиморфизма упрощает разработку и повышает гибкость в рамках объектно-ориентированной парадигмы.

Быстродействие. Показывает, насколько быстро осуществляется вызов кода исполнителя.

Системный API. Показывает возможность реализации системных API.

C++ API. Показывает возможность реализации C++ API.


Итак, объекты анализа выбраны, критерии определены. Теперь нужно построить матрицу соответствия. Для начала мы будем использовать качественный анализ, поскольку он более простой в реализации.

3.2. Качественный анализ

3.2.1. Матрица соответствия

Матрица соответствия строится в виде таблицы. В строках выписываются требования, в столбцах – способы реализации, в ячейках – признаки, указывающие, насколько реализация поддерживает соответствующий критерий (Табл. 7.)


Табл. 7. Качественный анализ реализаций обратных вызовов

Легенда: ▪ полностью поддерживается; ▫ поддерживается частично; пустое поле – не поддерживается


По каким соображениям мы назначили оценки?

Простота. Самой сложной реализацией будет, пожалуй, указатель на метод-член класса: запутанный и не слишком наглядный синтаксис. Довольно сложной выглядит реализация лямбда-выражений, поскольку приходится использовать шаблоны. Несколько проще выглядит реализация с помощью указателей на функцию, но там немного запутывает необходимость приведения типов. На этом фоне остальные реализации выглядят достаточно простыми.

Независимость компонентов. Полностью независимыми будет реализация с помощью указателей на функцию: как бы мы не модифицировали код исполнителя, как бы не меняли используемый контекст, код инициатора остается неизменным, даже не требуется его перекомпиляция. Это одна из причин, почему указанная реализация подходит для построения системных API. Лямбда-выражения являются относительно независимыми: при любом изменении состава и типов захваченных переменных код инициатора остается неизменным, но он будет требовать перекомпиляции, поскольку реализован с использованием шаблонов. Указатели на методы классов являются частично независимыми, поскольку требуют предварительного объявления класса в инициаторе. Использование функциональных объектов порождает монолитную архитектуру, где инициатор и исполнитель зависят друг от друга.

Отсутствие трансляции контекста. Указатели на функции и статические методы требуют трансляции контекста, остальные реализации этого не требуют.

Безопасность. Самыми безопасными являются функциональные объекты и лямбда- выражения, потому что в инициаторе хранятся их копии, никак не зависящие от исполнителя. Указатели на методы класса поддерживают безопасность лишь частично: управление временем жизни экземпляра класса возлагается на исполнителя, и потенциально возможны ситуации, когда последний уничтожает экземпляр класса, указатель на который остается в инициаторе и может быть вызван. Указатель на функцию не является безопасным, поскольку исполнитель интерпретирует контекст приведением типов, и нет никакой возможности проверить полученный указатель.

Гибкость. Самым гибким является указатель на метод класса, поскольку здесь имеются несколько способов модификации поведения обработчика. Другие реализации не предлагают таких возможностей, а функциональные объекты в силу монолитной структуры гибкими не являются.

Полиморфизм. Указатель на метод-член класса поддерживает полиморфизм подтипов (наследование и виртуализация), лямбда-выражения поддерживают специализированный полиморфизм (различный код в зависимости от состава и типов захваченных переменных). Остальные реализации полиморфизм не поддерживают.

Быстродействие. Самым быстродействующим является функциональный объект, практически не отстает от него и лямбда-выражение. Это связано с тем, что их код может встраиваться в точку вызова. Несколько медленнее работают указатели на функцию и на статический метод, поскольку их код выполняется через вызов функции13. Медленнее всего работает указатель на метод-член класса, поскольку ему необходимо обращение к таблице виртуальных функций.

Системный API. Указатель на функцию – единственный способ, с помощью которого можно использовать обратные вызовы при проектировании системных API.

C++ API. Лямбда-выражения не подходят для использования в C++ API: хотя инициатор не требует изменений при модификации исполнителя, но ему требуется перекомпиляция. Не подходят для С++ API также функциональные объекты, поскольку изменение функционального объекта затрагивает как инициатор, так и исполнитель.

3.2.2. Выбор реализации

Итак, мы построили матрицу соответствия, проанализировали, насколько реализации соответствуют выбранным критериям. Что же выбрать для конкретного случая? Для решения этого вопроса необходимо определить, какой критерий сейчас является наиболее важным, и выбрать реализацию по этому критерию. Так, например, если самым важным является возможность проектирования системного API, то следует выбрать указатели на функцию. Если самым важным является быстродействие, то следует выбрать функциональные объекты. Если самым важным является гибкость, то следует выбрать указатели на член класса.


Рекомендуем почитать
Pro Git

Разработчику часто требуется много сторонних инструментов, чтобы создавать и поддерживать проект. Система Git — один из таких инструментов и используется для контроля промежуточных версий вашего приложения, позволяя вам исправлять ошибки, откатывать к старой версии, разрабатывать проект в команде и сливать его потом. В книге вы узнаете об основах работы с Git: установка, ключевые команды, gitHub и многое другое.В книге рассматриваются следующие темы:основы Git;ветвление в Git;Git на сервере;распределённый Git;GitHub;инструменты Git;настройка Git;Git и другие системы контроля версий.


Java 7

Рассмотрено все необходимое для разработки, компиляции, отладки и запуска приложений Java. Изложены практические приемы использования как традиционных, так и новейших конструкций объектно-ориентированного языка Java, графической библиотеки классов Swing, расширенной библиотеки Java 2D, работа со звуком, печать, способы русификации программ. Приведено полное описание нововведений Java SE 7: двоичная запись чисел, строковые варианты разветвлений, "ромбовидный оператор", NIO2, новые средства многопоточности и др.


MFC и OpenGL

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


Симуляция частичной специализации

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


Обработка событий в С++

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


Питон — модули, пакеты, классы, экземпляры

Python - объектно-ориентированный язык сверхвысокого уровня. Python, в отличии от Java, не требует исключительно объектной ориентированности, но классы в Python так просто изучить и так удобно использовать, что даже новые и неискушенные пользователи быстро переходят на ОО-подход.