Как создать гибкую архитектуру плагинов? - PullRequest
145 голосов
/ 04 мая 2010

Повторяющейся темой в моей работе по разработке было использование или создание собственной архитектуры подключаемого модуля. Я видел, что он подходит ко многим параметрам - файлам конфигурации (XML, .conf и т. Д.), Структурам наследования, информации о базе данных, библиотекам и другим. По моему опыту:

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

Поскольку я стремлюсь учиться у различных архитектур, с которыми я работал, я также жду предложений от сообщества. Как вы реализовали архитектуру плагина SOLID? Какой был ваш худший провал (или худший провал, который вы видели)? Что бы вы сделали, если бы собирались реализовать новую архитектуру плагинов? Какой SDK или проект с открытым исходным кодом, с которым вы работали, имеет лучший пример хорошей архитектуры?

Несколько примеров, которые я нашел самостоятельно:

Эти примеры, похоже, играют на разных сильных сторонах языка. Обязательна ли хорошая архитектура плагинов к языку? Лучше ли использовать инструменты для создания плагин-архитектуры или делать это на своих собственных следующих моделях?

Ответы [ 8 ]

80 голосов
/ 07 мая 2010

Это не ответ , а целая куча потенциально полезных замечаний / примеров.

  • Один эффективный способ сделать ваше приложение расширяемым - это представить его внутреннее устройство как язык сценариев и написать все материалы верхнего уровня на этом языке. Это делает его вполне изменяемым и практически пригодным для будущего (если ваши примитивы правильно выбраны и реализованы). История успеха такого рода вещей - Emacs. Я предпочитаю это системе плагинов в стиле eclipse, потому что, если я хочу расширить функциональность, мне не нужно изучать API и писать / компилировать отдельный плагин. Я могу написать трехстрочный фрагмент в текущем буфере, оценить его и использовать. Очень плавная кривая обучения и очень приятные результаты.

  • Одно приложение, которое я немного расширил, это Trac . Он имеет компонентную архитектуру, которая в этой ситуации означает, что задачи делегируются модулям, которые объявляют точки расширения. Затем вы можете реализовать другие компоненты, которые будут вписываться в эти точки и изменить поток. Это немного похоже на предложение Калки выше.

  • Еще одна хорошая вещь - py.test . Он следует философии «лучший API - это не API» и основан исключительно на хуках, вызываемых на каждом уровне. Вы можете переопределить эти ловушки в файлах / функциях, названных в соответствии с соглашением, и изменить поведение. Вы можете увидеть список плагинов на сайте, чтобы увидеть, насколько быстро / легко они могут быть реализованы.

Несколько общих замечаний.

  • Постарайтесь, чтобы ваше нерасширяемое / не модифицируемое пользователем ядро ​​было как можно меньше. Передайте все, что можно, более высокому уровню, чтобы увеличить расширяемость. Меньше материала для исправления в основном, чем в случае неудачного выбора.
  • С этим связано то, что вы не должны принимать слишком много решений относительно направления вашего проекта с самого начала. Реализуйте наименьшее необходимое подмножество и затем начните писать плагины.
  • Если вы встраиваете язык сценариев, убедитесь, что он полный, на котором вы можете писать обычные программы, а не игрушечный язык просто для вашего приложения.
  • Уменьшите шаблон как можно больше. Не беспокойтесь о создании подклассов, сложных API, регистрации плагинов и тому подобном. Постарайтесь сделать это простым, чтобы легко , а не просто можно расширять. Это позволит более широко использовать API вашего плагина и побудит конечных пользователей писать плагины. Не только разработчики плагинов. py.test делает это хорошо. Затмение, насколько я знаю, не .
23 голосов
/ 07 мая 2010

По своему опыту я обнаружил, что на самом деле существует два типа подключаемых архитектур.

  1. Каждый следует за Eclipse model, который предназначен для предоставления свободы и является открытым.
  2. Другой обычно требует, чтобы плагины следовали за narrow API, потому что плагин будет выполнять определенную функцию.

Чтобы указать это по-другому, один позволяет плагинам получать доступ к вашему приложению , а другой позволяет вашему приложению получать доступ к плагинам .

Различие тонкое, и иногда нет различий ... вы хотите оба для вашего приложения.

У меня нет большого опыта работы с Eclipse / открытием вашего приложения для модели плагинов (статья в посте Калки великолепна). Я немного читал о том, как затмение что-то делает, но не более того.

Блог о свойствах Yegge немного рассказывает о том, как использование шаблона свойств обеспечивает плагины и расширяемость.

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

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

  • Теперь я обычно просто делаю DI framework большую часть этой работы.

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

14 голосов
/ 05 мая 2010

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

http://www.eclipse.org/articles/Article-Plug-in-architecture/plugin_architecture.html

8 голосов
/ 10 мая 2010

Однажды я работал над проектом, который должен был быть настолько гибким, чтобы каждый клиент мог настроить систему, и единственный хороший проект, который мы нашли, - это отправить клиенту компилятор C #!

Если спецификация заполнена такими словами, как:

  • Гибкий
  • Plug-In
  • Настраиваемый

Задайте много вопросов о том, как вы будете поддерживать систему (и как будет взиматься плата за поддержку, так как каждый клиент будет думать, что их случай - это обычный случай, и ему не нужно никаких плагинов.) 1013 *

Поддержка клиентов (или fount-line поддержка людей) написание Плагины намного сложнее, чем Архитектура

7 голосов
/ 04 мая 2010

Обычно я использую MEF. Managed Extensibility Framework (или MEF для краткости) упрощает создание расширяемых приложений. MEF предлагает возможности обнаружения и компоновки, которые вы можете использовать для загрузки расширений приложений.

Если вам интересно, прочитайте подробнее ...

6 голосов
/ 13 мая 2010

Я опишу довольно простую технику, которую я использовал в прошлом. Этот подход использует отражение C #, чтобы помочь в процессе загрузки плагина. Эту технику можно изменить, чтобы она применима к C ++, но вы теряете удобство использования отражения.

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

Для поиска плагинов приложение сканирует папку плагинов для сборок .Net. Каждая сборка загружена. Отражение используется для сканирования классов, которые реализуют IPlugin. Создается экземпляр каждого класса плагина.

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

Метод Init вызывается для каждого объекта плагина. Передается ссылка на объект, который реализует интерфейс приложения: IApplication (или что-то еще, названное специально для вашего приложения, например, ITextEditorApplication).

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

Эта система плагинов может быть расширена до языков сценариев, например, Lua, путем создания производного класса плагинов, например, LuaPlugin, который передает функции IPlugin и интерфейс приложения к сценарию Lua.

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

3 голосов
/ 12 мая 2010

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

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

Чтобы это работало, система сценариев должна иметь достаточно надежный API с привязками к данным приложения, логике и графическому интерфейсу, а также базовую функциональность импорта и выполнения кода из библиотек. Кроме того, сценарии обычно должны быть безопасными в том смысле, что приложение может корректно восстанавливаться из плохо написанного сценария. Использование системы сценариев в качестве слоя косвенности означает, что приложение может легче отсоединиться от себя в случае чего-то плохого & trade;.

Способ упаковки плагинов во многом зависит от личных предпочтений, но вы никогда не ошибетесь с сжатым архивом с простым интерфейсом, например, PluginName.ext в корневом каталоге.

3 голосов
/ 12 мая 2010

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

Я обнаружил, что принцип IOC (инверсия управления) (читай Springframework) хорошо работает для обеспечения гибкой базы,к которой вы можете добавить специализацию, чтобы упростить разработку плагинов.

  • Контейнер можно сканировать на предмет механизма «интерфейс как объявление типа плагина».
  • Контейнер можно использовать длявнедрить общие зависимости, которые могут потребоваться плагинам (например, ResourceLoaderAware или MessageSourceAware).
...