Un thème récurrent dans mon travail de développement a été l'utilisation ou la création d'une architecture plug-in en interne. Je l'ai vu abordé de nombreuses manières - fichiers de configuration (XML, .conf, etc.), cadres d'héritage, informations de base de données, bibliothèques, etc. Dans mon expérience:
- Une base de données n'est pas un bon endroit pour stocker vos informations de configuration, en particulier mélangées avec des données
- Tenter cela avec une hiérarchie d'héritage nécessite des connaissances sur les plug-ins à coder, ce qui signifie que l'architecture des plug-ins n'est pas si dynamique
- Les fichiers de configuration fonctionnent bien pour fournir des informations simples, mais ne peuvent pas gérer des comportements plus complexes
- Les bibliothèques semblent bien fonctionner, mais les dépendances unidirectionnelles doivent être soigneusement créées.
Alors que je cherche à apprendre des différentes architectures avec lesquelles j'ai travaillé, je me tourne également vers la communauté pour des suggestions. Comment avez-vous implémenté une architecture de plug-in SOLID? Quel a été votre pire échec (ou le pire échec que vous ayez vu)? Que feriez-vous si vous deviez implémenter une nouvelle architecture de plug-ins? Quel SDK ou projet open source avec lequel vous avez travaillé a le meilleur exemple d'une bonne architecture?
Quelques exemples que j'ai trouvés par moi-même:
- Module de Perl :: Plugable et IOC pour l'injection de dépendances en Perl
- Les différents frameworks Spring (Java, .NET, Python) pour l'injection de dépendances.
- Une question SO avec une liste pour Java (y compris les interfaces de fournisseur de services )
- Une question SO pour C ++ pointant vers un article de Dr. Dobbs
- Une question SO concernant une idée de plugin spécifique pour ASP.NET MVC
Ces exemples semblent jouer sur diverses forces linguistiques. Une bonne architecture de plugin est-elle nécessairement liée au langage? Est-il préférable d'utiliser des outils pour créer une architecture de plugin, ou de le faire sur ses propres modèles suivants?
Réponses:
Ce n'est pas une réponse autant qu'un tas de remarques / exemples potentiellement utiles.
Un moyen efficace de rendre votre application extensible consiste à exposer ses composants internes en tant que langage de script et à écrire tous les éléments de niveau supérieur dans ce langage. Cela le rend tout à fait modifiable et pratiquement à l'épreuve du temps (si vos primitives sont bien choisies et implémentées). Une histoire à succès de ce genre de chose est Emacs. Je préfère cela au système de plugins de style eclipse car si je veux étendre les fonctionnalités, je n'ai pas besoin d'apprendre l'API et d'écrire / compiler un plugin séparé. Je peux écrire un extrait de 3 lignes dans le tampon actuel lui-même, l'évaluer et l'utiliser. Courbe d'apprentissage très fluide et résultats très agréables.
Une application que j'ai un peu étendue est Trac . Il a une architecture de composants qui, dans cette situation, signifie que les tâches sont déléguées à des modules qui annoncent des points d'extension. Vous pouvez ensuite implémenter d'autres composants qui s'intégreraient dans ces points et modifier le flux. C'est un peu comme la suggestion de Kalkie ci-dessus.
Un autre bon est py.test . Il suit la philosophie «la meilleure API n'est pas une API» et repose uniquement sur les appels de hooks à tous les niveaux. Vous pouvez remplacer ces hooks dans les fichiers / fonctions nommés selon une convention et modifier le comportement. Vous pouvez voir la liste des plugins sur le site pour voir avec quelle rapidité / facilité ils peuvent être mis en œuvre.
Quelques points généraux.
la source
D'après mon expérience, j'ai trouvé qu'il existe vraiment deux types d'architectures de plug-ins.
Eclipse model
qui est censé permettre la liberté et est illimité.narrow API
car le plugin remplira une fonction spécifique.Pour indiquer cela d'une manière différente, l'un permet aux plugins d'accéder à votre application tandis que l'autre autorise votre application à accéder aux plugins .
La distinction est subtile, et parfois il n'y a pas de distinction ... vous voulez les deux pour votre application.
Je n'ai pas une tonne d'expérience avec Eclipse / Ouverture de votre application au modèle de plugins (l'article dans le post de Kalkie est génial). J'ai lu un peu sur la façon dont Eclipse fait les choses, mais rien de plus.
Le blog des propriétés de Yegge explique un peu comment l'utilisation du modèle de propriétés permet des plugins et de l'extensibilité.
La plupart du travail que j'ai effectué a utilisé une architecture de plugin pour permettre à mon application d'accéder à des plugins, des choses comme l'heure / l'affichage / les données cartographiques, etc.
Il y a des années, je créais des usines, des gestionnaires de plugins et des fichiers de configuration pour tout gérer et je me permettais de déterminer quel plugin utiliser au moment de l'exécution.
DI framework
faire la plupart de ce travail.Je dois encore écrire des adaptateurs pour utiliser des bibliothèques tierces, mais ils ne sont généralement pas si mauvais.
la source
L'une des meilleures architectures de plug-ins que j'ai vues est implémentée dans Eclipse. Au lieu d'avoir une application avec un modèle de plug-in, tout est un plug-in. L'application de base elle-même est le framework de plug-in.
http://www.eclipse.org/articles/Article-Plug-in-architecture/plugin_architecture.html
la source
Je vais décrire une technique assez simple que j'ai utilisée dans le passé. Cette approche utilise la réflexion C # pour aider dans le processus de chargement du plugin. Cette technique peut être modifiée pour être applicable au C ++, mais vous perdez la commodité de pouvoir utiliser la réflexion.
Une
IPlugin
interface est utilisée pour identifier les classes qui implémentent des plugins. Des méthodes sont ajoutées à l'interface pour permettre à l'application de communiquer avec le plugin. Par exemple, laInit
méthode que l'application utilisera pour demander au plugin de s'initialiser.Pour trouver des plugins, l'application scanne un dossier de plugins pour les assemblys .Net. Chaque assemblage est chargé. La réflexion est utilisée pour rechercher les classes qui implémentent
IPlugin
. Une instance de chaque classe de plugin est créée.(Sinon, un fichier Xml peut répertorier les assemblys et les classes à charger. Cela peut améliorer les performances mais je n'ai jamais trouvé de problème de performances).
La
Init
méthode est appelée pour chaque objet plugin. Il est passé une référence à un objet qui implémente l'interface de l'application:IApplication
(ou quelque chose d'autre nommé spécifique à votre application, par exemple ITextEditorApplication).IApplication
contient des méthodes qui permettent au plugin de communiquer avec l'application. Par exemple, si vous écrivez un éditeur de texte, cette interface aurait uneOpenDocuments
propriété qui permet aux plugins d'énumérer la collection de documents actuellement ouverts.Ce système de plugin peut être étendu aux langages de script, par exemple Lua, en créant une classe de plugin dérivée, par exemple
LuaPlugin
qui transmet lesIPlugin
fonctions et l'interface de l'application à un script Lua.Cette technique vous permet d'implémenter itérativement votre
IPlugin
,IApplication
et d' autres interfaces spécifiques d'application au cours du développement. Lorsque l'application est complète et bien refactorisée, vous pouvez documenter vos interfaces exposées et vous devriez avoir un système agréable pour lequel les utilisateurs peuvent écrire leurs propres plugins.la source
Habituellement, j'utilise MEF. Le Managed Extensibility Framework (ou MEF en abrégé) simplifie la création d'applications extensibles. MEF offre des fonctionnalités de découverte et de composition que vous pouvez utiliser pour charger des extensions d'application.
Si vous êtes intéressé, lisez plus ...
la source
Une fois, j'ai travaillé sur un projet qui devait être si flexible dans la façon dont chaque client pouvait configurer le système, dont la seule bonne conception que nous ayons trouvée était d'expédier au client un compilateur C #!
Si la spécification est remplie de mots comme:
Posez beaucoup de questions sur la manière dont vous soutiendrez le système (et comment l'assistance sera facturée, car chaque client pensera que son cas est le cas normal et ne devrait pas avoir besoin de plug-ins.), Comme dans mon expérience.
la source
D'après mon expérience, les deux meilleures façons de créer une architecture de plug-in flexible sont les langages de script et les bibliothèques. Ces deux concepts sont dans mon esprit orthogonaux; les deux peuvent être mélangés dans n'importe quelle proportion, un peu comme la programmation fonctionnelle et orientée objet, mais trouvent leurs plus grands atouts lorsqu'ils sont équilibrés. Une bibliothèque est généralement chargée de remplir une interface spécifique avec des fonctionnalités dynamiques, tandis que les scripts ont tendance à mettre l'accent sur les fonctionnalités avec une interface dynamique.
J'ai trouvé qu'une architecture basée sur des scripts gérant des bibliothèques semble fonctionner le mieux. Le langage de script permet une manipulation de haut niveau des bibliothèques de niveau inférieur, et les bibliothèques sont ainsi libérées de toute interface spécifique, laissant toute l'interaction au niveau de l'application entre les mains plus flexibles du système de script.
Pour que cela fonctionne, le système de script doit avoir une API assez robuste, avec des crochets aux données d'application, à la logique et à l'interface graphique, ainsi que la fonctionnalité de base d'importation et d'exécution de code à partir de bibliothèques. En outre, les scripts doivent généralement être sûrs dans le sens où l'application peut récupérer gracieusement d'un script mal écrit. L'utilisation d'un système de script comme couche d'indirection signifie que l'application peut se détacher plus facilement en cas de Something Bad ™.
Les moyens d'empaqueter les plugins dépendent en grande partie de vos préférences personnelles, mais vous ne pouvez jamais vous tromper avec une archive compressée avec une interface simple, par exemple
PluginName.ext
dans le répertoire racine.la source
Je pense que vous devez d'abord répondre à la question: "Quels composants sont censés être des plugins?" Vous voulez garder ce nombre à un minimum absolu ou le nombre de combinaisons que vous devez tester explose. Essayez de séparer votre produit principal (qui ne devrait pas avoir trop de flexibilité) de la fonctionnalité du plugin.
J'ai trouvé que le principal IOC (Inversion of Control) (read springframework) fonctionne bien pour fournir une base flexible, à laquelle vous pouvez ajouter une spécialisation pour simplifier le développement de plugins.
la source
Le modèle de plug-in est un modèle logiciel pour étendre le comportement d'une classe avec une interface propre. Le comportement des classes est souvent étendu par l'héritage de classe, où la classe dérivée écrase certaines des méthodes virtuelles de la classe. Un problème avec cette solution est qu'elle entre en conflit avec le masquage de l'implémentation. Cela conduit également à des situations où la classe dérivée devient un lieu de rassemblement d'extensions de comportement indépendantes. De plus, le script est utilisé pour implémenter ce modèle comme mentionné ci-dessus "Faites des internes comme langage de script et écrivez tous les éléments de haut niveau dans ce langage. Cela le rend tout à fait modifiable et pratiquement à l'épreuve du futur". Les bibliothèques utilisent des bibliothèques de gestion de scripts. Le langage de script permet une manipulation de haut niveau des bibliothèques de niveau inférieur. (Aussi comme mentionné ci-dessus)
la source