Python搭建插件式框架(基於組件開發)

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!