简单插件式编程实现

8 篇文章 0 订阅

最近接触到插件式编程,感觉是一种不错的思想。分享给大家

两种实现

  1. Golang的插件式编程
  2. C++的插件式编程

Golang的插件式编程

  1. 实现原理
    Golang的插件式实现主要依赖于自身的断言机制和接口实现。通过统一插件的接口后,规定实现的接口必须满足指定接口的实现,然后注册到插件管理类,外部使用时直接通过插件管理对象实现调用指定的插件。
    注意:插件式编程与插件是有区别的,插件式编程是一种规范,插件是对某一需求的完整实现。
  2. 源码示例
    2.1 接口的定义
package plugin

// 插件必须实现的接口
type (
	Plugin interface {
		Name() string
	}

	InitPlugin interface {
		Init() error
	}

	DoPlugin interface {
		Do() error
	}
)

2.2 注册插件、初始化插件、插件调用的实现

package plugin

import (
	"sync"
	"fmt"
)

var Pc = struct {
	plugins map[string]Plugin // 存放插件,插件名唯一<->插件
	mu      sync.Mutex
}{
	plugins:make(map[string]Plugin),
}

// 注册插件
func RegisterPlugin(plugins ...Plugin){
	if len(plugins) == 0{
		return
	}

	Pc.mu.Lock()

	for _,plugin := range plugins {
		if plugin == nil {
			fmt.Println("plugin cannot be nil")
			return
		}

		if _,ok := Pc.plugins[plugin.Name()]; ok {
			fmt.Println("repeat add plugin: %s", plugin.Name())
			return
		}

		Pc.plugins[plugin.Name()] = plugin
	}

	Pc.mu.Unlock()
}

// 调用左右插件的Init方法,初始化插件
func Init() error{
	for _,plugin := range Pc.plugins {
		if _plugin, ok := plugin.(InitPlugin); ok {
			if err := _plugin.Init(); err != nil {
				fmt.Printf("pluginContainer Init:%s, err:%v", plugin.Name(), err)
				return err
			}
		}
	}
	return nil
}

// 执行指定插件的Do操作
func Do(pluginName string) error {
	if plugin,ok := Pc.plugins[pluginName]; ok {
		if _plugin, ok := plugin.(DoPlugin); ok {
			if err := _plugin.Do(); err != nil {
				fmt.Println("pluginContainer Do:%s, err:%v", pluginName, err)
				return err
			}
		}
	}
	return nil
}

// 执行所有插件的Do操作
func DoAll() error {
	for _,plugin := range Pc.plugins {
		if _plugin, ok := plugin.(DoPlugin); ok {
			if err := _plugin.Do(); err != nil {
				fmt.Printf("pluginContainer Init:%s, err:%v", plugin.Name(), err)
				return err
			}
		}
	}
	return nil
}

3.1 现在我们来实现两个简单插件(hello.go,study.go),并在main.go中将实现的两个插件注册(RegisterPlugin)到插件管理中,并实现调用(Do)
hello.go

package hello

import "fmt"

var (
	PluginName = "HelloPlugin" // 插件名
)

type Hello struct {
	say string
}

func (p *Hello)Name() string {
	return PluginName
}

func (p *Hello)Init() error {
	fmt.Printf("init %s...\n", PluginName)
	p.say = "Hello World!"
	return nil
}

func (p *Hello)Do() error{
	fmt.Println(p.say)
	return nil
}

study.go

package study

import "fmt"

var (
	PluginName = "StudyPlugin"
)

type Study struct {
	study string
}

func (p *Study)Name() string{
	return PluginName
}

func (p *Study)Init() error{
	p.study = "Study English!"
	return nil
}

func (p *Study)Do() error{
	fmt.Println(p.study)
	return nil
}

main.go

package main

import (
	"../plugin/hello"
	"../plugin/plugins"
	"../plugin/study"
)

func main() {
	plugin.RegisterPlugin(new(hello.Hello), new(study.Study)) // 添加插件
	plugin.Init()                                             // 初始化所有插件对象

	plugin.Do(hello.PluginName) // 调用hello插件的Do方法
	plugin.Do(study.PluginName) // 调用study插件的Do方法
	plugin.DoAll()              // 调用所有插件的Do方法
}

运行结果:
$ go run main.go
init HelloPlugin…
Hello World!
Study English!
Hello World!
Study English!

C++的插件式编程

  1. 实现原理
    其实无论C++还是Golang对于插件式编程的实现,我觉得都是原理大同小异。只是不同的语言之间对某些专有名字的描述有差别。
    C++依赖于虚基类(多态),子类必须继承所需要实现的接口的虚基类,并实现其中的虚函数。调用的实现,即通过基类指针调用实现的虚函数。
  2. 源码示例
    2.1 接口定义 Interface.h
#pragma once
class CPluginInterface
{
public:
	virtual char* Name()= 0;
	virtual bool Init() = 0;
	virtual bool Do() = 0;
};

2.2 插件管理类 pluginMgr

#pragma once

#include "Interface.h"
#include <map>
using std::map;

class CPluginMgr
{
public:
	CPluginMgr();
	~CPluginMgr();

	void RegisterPlugin(CPluginInterface* plugin);
	void Init();
	void Do(char* pluginName);
	void DoAll();

private:
	map<char*, CPluginInterface*> m_pluginMap;
	bool m_target;
};
#include "pluginMgr.h"


CPluginMgr::CPluginMgr()
{
}


CPluginMgr::~CPluginMgr()
{
}

void CPluginMgr::RegisterPlugin(CPluginInterface* plugin)
{
	if (plugin) {
		m_pluginMap[plugin->Name()] = plugin;
	} else {
		printf("register plugin failed.");
	}
}

void CPluginMgr::Init()
{
	map<char*, CPluginInterface*>::iterator it = m_pluginMap.begin();
	while (it != m_pluginMap.end()) {
		printf("init %s\n", it->first);
		it->second->Init();
		it++;
	}
}

void CPluginMgr::Do(char * pluginName)
{
	CPluginInterface* plugin = m_pluginMap[pluginName];
	if (plugin) {
		plugin->Do();
	} else {
		printf("plugin %s Do failed.\n", pluginName);
	}
}

void CPluginMgr::DoAll()
{
	map<char*, CPluginInterface*>::iterator it = m_pluginMap.begin();
	while (it != m_pluginMap.end()) {
		it->second->Do();
		it++;
	}
}

2.3 插件Hello的是实现

#pragma once

#include "Interface.h"

class CHello:public CPluginInterface
{
public:
	CHello();
	~CHello();

	virtual char* Name() override;
	virtual bool Init() override;
	virtual bool Do() override;

private:
	char* m_pluginName;
	char* m_say;
};
#include "Hello.h"
#include <stdio.h>
#include <string.h>

CHello::CHello()
{
	m_say = new char[32]();
	m_pluginName = new char[32]();

	int len = strlen("HelloPlugin") + 1;
	strcpy_s(m_pluginName, len, "HelloPlugin");
}


CHello::~CHello()
{
	if (m_pluginName){
		delete m_pluginName;
	}

	if (m_say) {
		delete m_say;
	}
}

char * CHello::Name()
{
	return m_pluginName;
}

bool CHello::Init()
{
	strcpy_s(m_say, strlen("Hello World!")+1, "Hello World!");
	return true;
}

bool CHello::Do()
{
	printf("%s\n", m_say);
	return true;
}

2.4 main函数实现。注册Hello插件到插件管理类中,以及调用插件

#include <iostream>
#include "Hello.h"
#include "pluginMgr.h"

int main()
{
	CPluginMgr* mgr = new CPluginMgr();	// 初始化插件管理类
	CHello* h = new CHello();			// 初始化插件

	mgr->RegisterPlugin(h);				// 注册Hello插件到管理对象中
	mgr->Init();						// 初始化所有的插件
	mgr->Do(h->Name());					// 运行Hello插件
			
	system("pause");
}

完整源码:https://download.csdn.net/download/qq_30145355/10822584

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值