Python搭建插件式框架(基于组件开发)
- 2020 年 1 月 8 日
- 笔记
Python搭建插件式框架(基于组件开发)
概念
基于组件的开发(Component-Based Development,简称CBD)是一种软件开发范型。它是现今软件复用理论实用化的研究热点,在组件对象模型的支持下,通过复用已有的构件,软件开发者可以“即插即用”地快速构造应用软件。
优点
- 灵活性高:各个功能模块之间的耦合很低,每一个组件都是独立的,它附着在整个插件框架上执行,真正的实现有则加载,无则忽略。
- 复用性强:由于组件之间的通信或者交互都是通过插件框架提供的接口来执行,各个组件之见是遵守依赖倒置原则的。所以无论需要哪个模块的功能,都只需要将该插件直接拿走复用即可。
框架描述
之前有这么一个有趣的笑话。说一个人一大早起来想吃火锅,但是他又不想出门,于是他想了个主意,他给A打电话说:今天请大家吃火锅,别的东西都有了,就差一份羊肉了,来的时候带着。完了给B打电话说:今天请大家吃火锅,别的东西都有的,火锅料忘了买了,来的时候捎上……,他用这样的方法将所有的菜凑够,足不出户,就能吃火锅,而且想吃啥就吃啥。
这个例子中,这个在家里想吃火锅并且挨个给大家打电话的人便是插件式框架中的总框架,本身不提供任何的功能,角色就是总指挥。而小A,小B这些朋友则是各个组件,自己只负责自己的部分,但是每一个组件都无法单独执行,只能在总框架中执行。组件为整个开发提供基本的功能,组件之间的通信也都是通过总框架来实现的,这就是整个插件式框架。
实现
相信点开看这篇文章的都是有一定Python基础并且遇到类似于插件式开发需求,从而来看一份有用的代码,再将其拷贝走的。话不多说,上代码吧。
目录结构
++PluginFrame
– main.py
– PluginManager
++ Plugins
-- Plugin1.py -- Plugin2.py -- Plugin3.py -- Plugin4.py
### 插件式框架 import os import sys from imp import find_module from imp import load_module class PluginManager(type): #静态变量配置插件路径 __PluginPath = 'Plugins' #调用时将插件注册 def __init__(self,name,bases,dict): if not hasattr(self,'AllPlugins'): self.__AllPlugins = {} else: self.RegisterAllPlugin(self) #设置插件路径 @staticmethod def SetPluginPath(path): if os.path.isdir(path): PluginManager.__PluginPath = path else: print '%s is not a valid path' % path #递归检测插件路径下的所有插件,并将它们存到内存中 @staticmethod def LoadAllPlugin(): pluginPath = PluginManager.__PluginPath if not os.path.isdir(pluginPath): raise EnvironmentError,'%s is not a directory' % pluginPath items = os.listdir(pluginPath) for item in items: if os.path.isdir(os.path.join(pluginPath,item)): PluginManager.__PluginPath = os.path.join(pluginPath,item) PluginManager.LoadAllPlugin() else: if item.endswith('.py') and item != '__init__.py': moduleName = item[:-3] if moduleName not in sys.modules: fileHandle, filePath,dect = find_module(moduleName,[pluginPath]) try: moduleObj = load_module(moduleName,fileHandle,filePath,dect) finally: if fileHandle : fileHandle.close() #返回所有的插件 @property def AllPlugins(self): return self.__AllPlugins #注册插件 def RegisterAllPlugin(self,aPlugin): pluginName = '.'.join([aPlugin.__module__,aPlugin.__name__]) pluginObj = aPlugin() self.__AllPlugins[pluginName] = pluginObj #注销插件 def UnregisterPlugin(self,pLuginName): if pluginName in self.__AllPlugins: pluginObj = self.__AllPlugins[pluginName] del pluginObj #获取插件对象。 def GetPluginObject(self, pluginName = None): if pluginName is None: return self.__AllPlugins.values() else: result = self.__AllPlugins[pluginName] if pluginName in self.__AllPlugins else None return result #根据插件名字,获取插件对象。(提供插件之间的通信) @staticmethod def GetPluginByName(pluginName): if pluginName is None: return None else: for SingleModel in __ALLMODEL__: plugin = SingleModel.GetPluginObject(pluginName) if plugin: return plugin #插件框架的接入点。便于管理各个插件。各个插件通过继承接入点类,利用Python中metaclass的优势,将插件注册。接入点中定义了各个插件模块必须要实现的接口。 class Model_Component(object): __metaclass__ = PluginManager def Start(self): print 'Please write the Start() function' def ChangeLanguage(self,language): print 'Please write the ChangeLanguage() function' class Model_MenuObj(object): __metaclass__ = PluginManager def Start(self): print 'Please write the Start() function' def ChangeLanguage(self,language): print 'Please write the ChangeLanguage() function' class Model_ToolBarObj(object): __metaclass__ = PluginManager def Start(self): print 'Please write the Start() function' def ChangeLanguage(self,language): print 'Please write the ChangeLanguage() function' class Model_ParamPanelObj(object): __metaclass__ = PluginManager def Start(self): print 'Please write the Start() function' def ChangeLanguage(self,language): print 'Please write the ChangeLanguage() function' __ALLMODEL__ = (Model_ParamPanelObj,Model_ToolBarObj,Model_MenuObj,Model_Component)
#插件1 from PluginManager import Model_MenuObj class Plugin1(Model_MenuObj): def __init__(self): pass #实现接入点的接口 def Start(self): print "I am plugin1 , I am a menu!"
#插件2 from PluginManager import Model_ToolBarObj class Plugin2(Model_ToolBarObj): def __init__(self): pass def Start(self): print "I am plugin2 , I am a ToolBar!"
#插件3 from PluginManager import Model_ParamPanelObj class Plugin3(Model_ParamPanelObj): def __init__(self): pass def Start(self): print "I am plugin3 , I am a ParamPanel!"
#插件4 from PluginManager import Model_Component class Plugin4(Model_Component): def __init__(self): pass def Start(self): print "I am plugin4 , I am a Component!"
#main调用 import sys from PluginManager import PluginManager from PluginManager import __ALLMODEL__ if __name__ == '__main__': #加载所有插件 PluginManager.LoadAllPlugin() #遍历所有接入点下的所有插件 for SingleModel in __ALLMODEL__: plugins = SingleModel.GetPluginObject() for item in plugins: #调用接入点的公共接口 item.Start()
输出
I am plugin3 , I am a ParamPanel!
I am plugin2 , I am a ToolBar!
I am plugin1 , I am a menu!
I am plugin4 , I am a Component!