Як створити гнучку архітектуру плагінів?


154

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

  • База даних не є чудовим місцем для зберігання вашої конфігураційної інформації, особливо сумісно з даними
  • Спроба цього за допомогою ієрархії спадкування вимагає кодування значень про плагіни, тобто архітектура плагінів не все така динамічна
  • Файли конфігурації добре допомагають надавати просту інформацію, але не можуть обробляти складніші способи поведінки
  • Бібліотеки, здається, працюють добре, але односторонні залежності потрібно ретельно створювати.

Оскільки я прагну вчитися в різних архітектурах, з якими працював, я також звертаюся до громади для пропозицій. Як ви реалізували архітектуру плагінів SOLID? Який був ваш найгірший провал (чи найгірший невдача, який ви бачили) Що б ви зробили, якби збиралися впроваджувати нову архітектуру плагінів? Який SDK або проект з відкритим кодом, з яким ви працювали, є найкращим прикладом хорошої архітектури?

Кілька прикладів, які я знаходив самостійно:

Ці приклади, схоже, грають на різні мовні сили. Чи хороша архітектура плагінів обов'язково пов'язана з мовою? Краще використовувати інструменти для створення архітектури плагінів або робити це на власних наступних моделях?


Чи можете ви сказати, чому архітектура плагінів була загальною темою? Які проблеми вона вирішує, або цілі вирішує? У багатьох розширюваних системах / додатках використовуються плагіни певної форми, але форма значно відрізняється залежно від проблеми, яка вирішується.
mdma

@mdma - це чудове питання. Я б сказав, що в розширюваній системі є деякі загальні цілі. Можливо, цілі - це все, що є загальним, і найкраще рішення варіюється залежно від того, наскільки розширеною має бути система, якою мовою система написана тощо. Однак я бачу, що шаблони, такі як IOC, застосовуються у багатьох мовах, і мене просять робити подібні плагіни (для падіння шматочків, що відповідають на ті самі запити функціоналу) знову і знову. Я думаю, що добре отримати загальне уявлення про кращі практики для різних типів плагінів.
justkt

Відповіді:


89

Це не така відповідь , як купа потенційно корисних зауважень / прикладів.

  • Один ефективний спосіб зробити вашу програму розширюваною - це розкрити її внутрішні мови як сценарій мови та записати всі матеріали верхнього рівня цією мовою. Це робить його досить видозміненим і практично майбутнім доказом (якщо ваші примітиви будуть правильно обрані та реалізовані). Історія успіху подібної речі - Emacs. Я віддаю перевагу це системі плагінів у стилі eclipse, тому що якщо я хочу розширити функціонал, мені не доведеться вивчати API та писати / компілювати окремий плагін. Я можу написати фрагмент 3 рядка в поточний буфер, оцінити його і використовувати. Дуже гладка крива навчання та дуже приємні результати.

  • Один додаток, який я трохи продовжив - Trac . Він має архітектуру компонентів, що в цій ситуації означає, що завдання делеговані модулям, які рекламують точки розширення. Потім можна реалізувати інші компоненти, які б вписалися в ці точки і змінили потік. Це трохи нагадує пропозицію Калкі вище.

  • Ще один хороший - py.test . Це дотримується філософії "кращий API - це не API" і покладається виключно на виклики гачків на кожному рівні. Ви можете змінити ці гачки у файлах / функціях, названих відповідно до конвенції, та змінити поведінку. Ви можете переглянути список плагінів на сайті, щоб побачити, наскільки швидко / легко вони можуть бути реалізовані.

Кілька загальних моментів.

  • Постарайтеся, щоб ваш нерозширюваний / не змінюваний користувачем сердечник був якомога меншим. Делегуйте все, що можна, на більш високий шар, щоб розширюваність збільшувалася. Менше речей для виправлення в основному, якщо у випадку поганого вибору.
  • Пов’язане з вищезазначеним моментом полягає в тому, що ви не повинні спочатку приймати занадто багато рішень щодо напрямку вашого проекту. Реалізуйте найменший необхідний підмножина, а потім починайте писати плагіни.
  • Якщо ви вбудовуєте мову сценаріїв, переконайтеся, що це повна мова, в якій ви можете писати загальні програми, а не мова іграшки лише для вашої програми.
  • Скоротіть котельну плиту максимально. Не турбуйтеся про підкласифікацію, складні API, реєстрацію плагінів тощо. Постарайтеся зробити це простим, щоб його було легко і не просто можна було продовжити. Це дозволить вашому API плагінів більше використовуватись і заохочуватиме кінцевих користувачів писати плагіни. Не лише розробники плагінів. py.test робить це добре. Затемнення, наскільки я знаю, не робить .

1
Я хотів би зазначити мову сценаріїв до того, що варто розглянути можливість вбудувати існуючу мову на зразок python або perl
Rudi

Справжній Руді. Багато мов робляться такими, що розроблені для вбудовування. Наприклад, Guile зроблений просто для вбудовування. Це економить час, якщо ви зробите ваш додаток сценарієм. Ви можете просто перейти на одну з цих мов.
Нуфал Ібрагім

24

З мого досвіду я виявив, що існує справді два типи архітектур плагінів.

  1. Випливає, Eclipse modelщо має на меті забезпечити свободу і є відкритим.
  2. Інший, як правило, вимагає, щоб плагіни слідували a, narrow APIоскільки плагін заповнить певну функцію.

Щоб констатувати це по-іншому, один дозволяє плагінам отримати доступ до вашої програми, а інший дозволяє вашій програмі отримати доступ до плагінів .

Відмінність тонка, і іноді немає ніяких розчарувань ... ви хочете як для своєї заявки.

Я не маю багато досвіду роботи з Eclipse / Openning your App to plugins model (стаття в дописі Kalkie чудова). Я читав трохи про те, як затемнення робить речі, але не більше того.

Блог властивостей Yegge трохи розповідає про те, як використання шаблону властивостей забезпечує плагіни та розширення.

Більшість робіт, які я виконував, використовувала архітектуру плагінів, щоб дозволити моїй програмі отримувати доступ до плагінів, таких як час / показ / дані карт тощо.

Роки тому я створив би фабрики, менеджери плагінів і конфігураційні файли, щоб керувати усім цим, і дозволив мені визначити, який плагін використовувати під час виконання.

  • Зараз я зазвичай просто DI frameworkвиконую більшу частину цієї роботи.

Мені все одно доводиться писати адаптери для використання сторонніх бібліотек, але вони зазвичай не такі вже й погані.


@ Джастін так, DI = введення залежності.
виведення

14

Одна з найкращих архітектур плагінів, яку я бачив, реалізована в Eclipse. Замість того, щоб мати додаток із плагінною моделлю, все є плагіном. Сам базовий додаток - це плагін.

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


Звичайно, хороший приклад, але чи він більший і складніший, ніж вимагає багато додатків?
justkt

Так, це може бути, збільшення гнучкості пов'язане з вартістю. Але я думаю, що це показує іншу точку зору. Чому меню вашої програми не може бути плагіном чи основним видом?
Патрік

6
Той самий підхід (усе є плагіном) використовується в новій версії рамки Symfony. Їх називають розшаруваннями, але принцип той же. Її архітектура досить проста, можливо, ви повинні подивитися на неї: symfony-reloaded.org/quick-tour-part-4
Marijn Huizendveld,

@Marjin Huizendveld - ви повинні додати це як окрему відповідь, щоб я міг схвалити відповідь. Виглядає як цікава рамка!
justkt

11

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

IPluginІнтерфейс використовується для визначення класів, що реалізують плагінів. Методи додаються в інтерфейс, щоб програма могла спілкуватися з плагіном. Наприклад, Initметод, який буде застосовано програмою для вказівки плагіна на ініціалізацію.

Щоб знайти плагіни, програма сканує папку плагінів для збірок .Net. Кожна збірка завантажена. Рефлексія використовується для сканування класів, які реалізують IPlugin. Створюється екземпляр кожного класу плагінів.

(Крім того, XML-файл може перелічити збірки та класи для завантаження. Це може сприяти продуктивності, але я ніколи не знайшов проблеми з продуктивністю).

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

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

Ця система плагінів може бути розширена до мов скриптів, наприклад, Lua, створивши похідний клас плагінів, наприклад, LuaPluginщо пересилає IPluginфункції та інтерфейс програми до сценарію Lua.

Цей метод дозволяє итеративно реалізувати свої IPlugin, IApplicationі інші додатки конкретних інтерфейсів в процесі розробки. Коли програма буде завершена і добре відновлена, ви можете документувати відкриті інтерфейси, і у вас повинна бути приємна система, для якої користувачі можуть писати власні плагіни.


7

Зазвичай я використовую MEF. Рамка керованої розширюваності (або короткий MEF) спрощує створення розширюваних програм. MEF пропонує можливості відкриття та композиції, які можна використовувати для завантаження розширень додатків.

Якщо ви зацікавлені читайте докладніше ...


Спасибі, виглядає цікаво. Наскільки легко застосовувати подібні принципи на інших мовах?
justkt

Насправді MEF призначений лише для .NET Framework Я нічого не знаю про інші рамки
BALKANGraph

7

Я колись працював над проектом, який повинен був бути настільки гнучким, щоб кожен клієнт міг налаштувати систему, і єдиний хороший дизайн, який ми знайшли, - це доставити клієнту компілятор C #!

Якщо специфікація заповнена такими словами:

  • Гнучка
  • Підключати
  • Настроюється

Задайте багато запитань щодо того, як ви будете підтримувати систему (і як буде стягуватися плата за підтримку, оскільки кожен клієнт буде вважати, що їх випадок - це звичайний випадок і не потребує ніяких плагінів.), Як на моєму досвіді

Підтримка клієнтів (або людей, які надають фундаментальну підтримку) писати плагіни набагато важче, ніж архітектура


5

На мій досвід, два найкращі способи створення гнучкої архітектури плагінів - це написання мов та бібліотек. Ці два поняття на мою думку є ортогональними; вони можуть бути змішані в будь-якій пропорції, швидше, як функціональне та об'єктно-орієнтоване програмування, але знаходять свої найбільші сильні сторони при збалансованості. Бібліотека, як правило, відповідає за виконання певного інтерфейсу з динамічним функціоналом, тоді як сценарії, як правило, підкреслюють функціональність з динамічним інтерфейсом.

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

Для цього система сценаріїв повинна мати досить надійний API, з гачками до даних програми, логікою та графічним інтерфейсом, а також базовим функціоналом імпорту та виконання коду з бібліотек. Крім того, сценарії, як правило, вимагають бути безпечними в тому сенсі, що програма може витончено відновитися після погано написаного сценарію. Використання системи сценаріїв як шару непрямості означає, що програма може легше відшаруватися у випадку чогось поганого ™.

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


3

Думаю, вам потрібно спочатку відповісти на питання: "Які компоненти очікують плагіни?" Ви хочете, щоб це число було абсолютним мінімумом або кількість комбінацій, які ви повинні випробувати вибухає. Спробуйте відокремити основний продукт (який не повинен мати занадто великої гнучкості) від функціональності плагінів.

Я виявив, що керівник IOC (Inversion of Control) (читайте springframework) добре працює для забезпечення гнучкої бази, до якої ви можете додати спеціалізацію, щоб спростити розробку плагінів.

  • Ви можете сканувати контейнер на механізм "інтерфейс як рекламний модуль".
  • Ви можете використовувати контейнер для введення загальних залежностей, які можуть потребувати плагіни (наприклад, ResourceLoaderAware або MessageSourceAware).

1

Модель плагіна - це програмний зразок для розширення поведінки класу з чистим інтерфейсом. Часто поведінка класів поширюється на спадкування класів, де похідний клас перезаписує деякі віртуальні методи класу. Проблема цього рішення полягає в тому, що воно суперечить приховуванню реалізації. Це також призводить до ситуацій, коли похідний клас стає місцем збору непов'язаних розширень поведінки. Крім того, сценарій використовується для реалізації цього шаблону, як згадувалося вище "Зробити внутрішні дані як мову сценаріїв і записати всі матеріали верхнього рівня на цій мові. Це робить його досить видозміненим і практично підтверджує майбутнє". Бібліотеки використовують бібліотеки управління сценаріями. Мова сценаріїв дозволяє здійснювати високоякісні маніпуляції з бібліотеками нижчого рівня. (Також як зазначено вище)

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.