Как стать автором
Обновить

Не умер ли еще Microsoft COM, где можно найти его применение?

Уровень сложностиСредний
Время на прочтение7 мин
Количество просмотров8.1K

К написанию статьи меня подтолкнул вот такой вопрос:

Всем добрый день. Хотел бы получить краткие и понятные для новичка ответы на следующие вопросы:

  1. Что такое COM объект?

  2. Как происходит разработка COM объекта?

  3. Какие особенности реализации COM Microsoft?

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

Ниже предлагаю свой развернутый ответ, который, почему-то, неизменно возбуждает вопрос из нового заголовка статьи. Интересно было получить оценку сообщества профессионалов. Надеюсь и новички смогут найти что то полезное.


COM объект – это объект, созданный-описанный-реализованный по правилам COM. Одним из основных правил COM является способ идентификации COM объектов по функциональности, которую они реализуют. Чтобы все-таки понять, что такое COM объект нам бы пришлось изучить не только достаточно обширную документацию по разработке COM объектов, но и разобрать хотя бы один практический пример, для которого применяется эта технология. Таким образом ответ на второй вопрос фактически является ответом и на первый вопрос.

Кстати в документации Майкрософта по DirectX, практически в заголовке мы также, как и 20+ лет назад, видим заявление о необходимости использования СОМ:

The Microsoft Component Object Model (COM) is an object-oriented programming model used by several technologies, including the bulk of the DirectX API surface. For that reason, you (as a DirectX developer) inevitably use COM when you program DirectX.

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

Для примера можно рассмотреть задачу создания универсального проигрывателя видео файлов (видеоплеер).

Проблема сложности реализации (не путать со сложностью вычислений в ран-тайме)

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

Для осознания масштаба той программы, которая будет претендовать на универсальность, при проигрывании видео, допустим у нас есть по 10 форматов каждого типа. Таким образом наш универсальный проигрыватель видео должен уметь обрабатывать 10 * 10 * 10 = 1000 вариантов конфигурации проигрываемого файла, представьте себе switch на тысячу кейсов! Это конечно очень грубая абстракция для оценки масштаба программы для проигрывания видео, но, как ни странно, она дает очень наглядную и совершенно адекватную оценку масштаба проблемы, которую надо решить. Очевидно что в одном случае сложность определяется произведением целых чисел больших единицы, а в другом суммой плюс некоторая константа сравнимая с единицей. Кстати, по поводу оценки 10 «десять» вариантов – для тех, кто не в курсе – это очень умеренная оценка количества, в реальности это число оценивается в несколько десятков и, типов кодеков на самом деле, гораздо больше, чем три.

Решение как обычно будет очевидным после того, как оно кем-то сформулировано. Вместо того что бы писать 1000 вариантов алгоритма на каждый из случаев жизни, надо:

  1. Написать отдельную компоненту (библиотеку‑DLL‑ку) для каждого декодера, распаковщика, рендерера, …, то есть в рассмотренном случае всего 30 ДЛЛ‑к вместо 1000 кейсов в свиче!

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

Для тех, кто любит считать сложность по формулам, исходная была:

O (произведение всех ni для всех m типов кодеков) где

ni – число кодеков одного типа i,

m – число типов кодеков.

Во втором случае сложность равна:

O(суммы Ni  для m типов + L) где

Ni – число кодеков одного типа i оформленных в виде компонент,

m – число типов кодеков и

L – сложность логики из пункта 2. Кажется, что N будет несколько выше, чем n так как нужно какое-то дополнительное оформление, на самом деле это оформление зачастую упрощает разработку так как заставляет сосредоточиться на действительно значимых аспектах реализации компоненты и обеспечивает существенный уровень унификации кода.

Есть отдельный огромный плюс компонентного подхода. У нас появляется возможность разрабатывать декодеры (например, для примера Mpeg4, MP4) совершенно изолированно друг от друга, в разных проектах, разными людьми, параллельно, … как угодно! Единственное условие соответствие разработанной компоненты определенным правилам оформления компонент.

И теперь можно остановиться на этих правилах оформления компонент поподробнее, их все равно надо понимать в каком-то виде для понимания всей технологии. Чтобы понять эти правила надо попробовать сформулировать логику по которой будет строиться и работать приложение видео плеера, основанное на использовании кодеков, каждый из которых может загружаться из отдельной ДЛЛ-ки.

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

Как это выглядит на каком-то подобии схемы

На картинке ниже можно видеть обычный результат работы видеоплеера при открытии файла. Результатом является граф построенный из найденных, загруженных и состыкованных для передачи-приема данных компонент разного типа необходимых для парсинга, декодирования и отображения данных после нажатия кнопки «плей».

Как это ни странно в мире COM-объектов видео плеер НЕ декодирует, НЕ проигрывает видео сам, он строит связанный граф из компонент, которые будут проигрывать видео, а ПОТОМ транслирует пользовательские команды (такие как нажатие кнопок Стоп-Плей) в команды для этого графа. Уходя немного в сторону, можно отметить что граф тоже представлен некоторым объектом внутри видеоплеера и трансляция пользовательских команд к этому объекту тоже во многом регламентирована, не уверен что в рамках СОМ технологии.

Я уже отметил, что метод оценки сложности реализации функциональности, который я использовал очень грубый (хотя и адекватный по полученным результатам). Если мы даже немного погрузимся в детали того как выбирается нужный кодек для очередного этапа обработки данных, например декодирования, мы увидим что даже отдельный кодек зависит не только от типа данных в стриме который ему надо обрабатывать но и от того, например, каким образом эти данные ему скармливает предыдущий кодек (например МР4 декодер должен получить данные от файл-реадера который соответствующим образом парсит файл-екстрактит видео и аудио потоки). По поводу всего этого растущего с глубиной реализации многообразия можно отметить, что все это многообразие успешно управляется в рамках концепции COM объектов. COM технологии позволяют поддерживать управляемость кода, избегать древней, но все такой же актуальной проблемы известной под названием DLL HELL.

Я думаю, теперь вполне понятно, что смысл СОМ технологии или концепции состоит в том чтобы разбить решение одной очень объемной задачи, такой как разработка универсального видео плеера на множество подзадач которые можно решить независимо друг от друга. Нетрудно понять, что решение, которое делит огромную монолитную программу на множество независимых компонент и некоторое легковесное ядро для связывания этих компонент в законченное приложение требует поддержки со стороны операционной системы. Операционная система должна обеспечить поиск нужной компоненты для обработки выявленного формата данных, по сути ОС должна поддерживать базу данных исполняемых компонент и их описаний для того чтобы компоненты (обычно в виде ДЛЛ-к) можно было добавлять/регистрировать в этой базе данных, а потом находить и активировать-использовать эти компоненты по системе идентификации определенной в этой базе данных. Система идентификации компонент также является одной из глобальных инфраструктурных функций ОС, компоненты получают идентификаторы не зависимо от того добавлены они уже в базу данных компонент операционной системы или нет.

Фабрики классов и другие паттерны проектирования

Интересно отметить, что, например, применение паттерна проектирования с «фабриками классов» является неотъемлемой частью СОМ технологии. Чтобы иметь возможность создавать объекты классов, реализованных в ДЛЛ-ке по идентификатору (или по некоторой структуре с описанием функциональности требуемого объекта) каждая ДЛЛ-ка реализует один или несколько классов-фабрик для компонент, эти же классы-фабрики вызываются для получения информации о содержимом ДЛЛ-ки при регистрации в базе данных компонент.

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

Третий вопрос: Какие особенности реализации COM Microsoft?

Честно говоря, для меня вопрос выглядит не корректно. На сколько я знаю СОМ технология реализована только Мелко-Мягкими :). А анализ особенностей предполагает сравнение с какой-то другой реализацией, а другой реализации просто не существует, по крайней мере я таких не знаю.

Интересно в качестве ответа на 3-й вопрос попытаться сравнить КОМ технологию с какой-то в чем то сравнимой и/или чем-то похожей технологией. Возьмем для примера (неожиданно) технологию инстанциирования (создания, внедрения, …) объектов-бинов из Java Spring.

MS COM по сути тоже является технологией инстанциирования COM объектов

В какой-то степени Dependency Injection является интерпретацией идей создания объектов класса по его идентификатору, помноженной на идею создания некоторого универсального алгоритма для инстанциирования объектов на основе анализа кода.

Таким образом Dependency Injection для бинов из Java Spring мне представляется в каком то смысле развитием и переносом в новый контекст идей, изначально сформулированных в рамках СОМ технологии. При этом я совершенно не исключаю что СОМ технология также в свое время была развитием и переносом в новый контекст идей, изначально сформулированных где-то еще раньше. Я не историк, я разработчик, историческая точность для меня не стоит на первом месте.

Теги:
Хабы:
Всего голосов 11: ↑3 и ↓8-4
Комментарии47

Публикации

Истории

Работа

Программист C++
107 вакансий
QT разработчик
4 вакансии

Ближайшие события

7 – 8 ноября
Конференция byteoilgas_conf 2024
МоскваОнлайн
7 – 8 ноября
Конференция «Матемаркетинг»
МоскваОнлайн
15 – 16 ноября
IT-конференция Merge Skolkovo
Москва
22 – 24 ноября
Хакатон «AgroCode Hack Genetics'24»
Онлайн
28 ноября
Конференция «TechRec: ITHR CAMPUS»
МоскваОнлайн
25 – 26 апреля
IT-конференция Merge Tatarstan 2025
Казань