专栏首页python3Python搭建插件式框架(基于组件开发)

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!

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • python之nntp服务器组

    这个项目的目的就是收集信息,并且将其生成一个html的报告(当然也可以是其他的形式的报告),完成代码如下

    py3study
  • python self

    最近在看python的一些代码,学习并且要掌握这些在短期内还是有一点难度的,日积月累,浮躁是个大问题。对于一个基本没从事过开发的我来说,看到python sel...

    py3study
  • 用python实现选择截图区域

    一直想用python实现一个类似QQ截图的功能,但不直接截图,而是返回截图的区域,以下是代码

    py3study
  • 插图设计正流行,10大理由告诉你如何靠它增强用户体验

    过去的几年中,用户界面中加入插图一直是最受欢迎也最稳固的设计趋势之一。今天,摹客的小伙伴将带领大家一起讨论设计师在网页或移动APP的UI设计,尤其是核心视觉元素...

    奔跑的小鹿
  • Python性能测试locust(二)

    “Locust是一个用于可扩展的,分布式的,性能测试的,开源的,用Python编写框架/工具,它非常容易使用,也非常好学。它的主要思想就是模拟一群用户访问你的网...

    周萝卜
  • 2019-2020内容产业趋势报告:七个黄金拐点=七个机会

    生产模式变革(已完成); 分发模式变革(进行中)。 Next……? 随着自媒体生态的出现,和人工智能对内容分发的改造,这场覆盖内容产业端到端的革新,终于迎来...

    腾讯大讲堂
  • MySQL创建表失败的问题

    今天有一个朋友问我一个MySQL的建表问题,问题的现象是创建表失败,根据他的反馈,问题比较奇怪, CREATE TABLE XXX ..此处省略260多个字...

    jeanron100
  • Spring Cloud Stream应用与自定义RocketMQ Binder:编程模型

    前言: 本文作者张天,节选自笔者与其合著的《Spring Cloud微服务架构进阶》,即将在八月出版问世。将其中Spring Cloud Stream应用与自定...

    aoho求索
  • 使用Spring Cloud Stream 构建消息驱动微服务

    Spring Cloud Stream is a framework for building message-driven microservice appl...

    烂猪皮
  • 《一头扎进》系列之Python+Selenium框架实战篇8 - 年底升职加薪,年终奖就差最后这一步你知道不???

      到上一篇为止,测试报告已经完美的生成,但是你此时不要沾沾自喜,因为还差点意思,你才能升职加薪、拿年终奖。差点啥了???听宏哥给你慢慢道来。那就是把你生成的高...

    北京-宏哥

扫码关注云+社区

领取腾讯云代金券