正向(或者前向)插件系统设计

正向插件系统通过预先定义接口并使用共享库实现功能的动态加载和选择,达到运行时策略选择和模块化测试的效果。例如,Adobe Photoshop中对文件格式和滤镜的支持就运用了这种设计模式。
摘要由CSDN通过智能技术生成

       正向插件系统指的是在设计之初就已经定义好了一族用于特定功能的接口,然后通过共享库的形式隔离不同的实现策略,这样做不仅可以做到运行时按需选择实现策略,而且非常有利于功能的模块化测试。这种模式的插件系统是非常常见的,比如Adobe PS 对于不同文件格式、不同滤镜等的支持就是采用的就是正向插件系统设计。

      现在我们来看一下这样的计算器程序怎么使用正向插件系统的思想进行实现。 首先,我们在源代码中实现一个简单的加法运算:从控制台输入两个数字,然后输出这两个数字的和。

主项目main.c的代码如下:

#include <stdio.h> #include <stdlib.h> #include <dlfcn.h> #include <assert.h> typedef int (*calc_t)(int a, int b); int main() { void* module = dlopen("./libadd.dylib", RTLD_NOW); assert(module != NULL); calc_t calc = (calc_t) dlsym(module, "calc"); assert(calc != NULL); do { int i_first; printf("input the first number:"); scanf("%d", &i_first); int i_second; printf("input the second number:"); scanf("%d", &i_second); int i_result = (*calc)(i_first, i_second); printf("the result is %d\n\n", i_result); } while (true); dlclose(module); return 0; }

libadd项目的add.cpp文件内容如下:

extern "C" int calc(int a, int b) { return a + b; }

我们看到程序能够正确的运行,但是现在我们只实现了一个+的插件,我们继续实现-、*、/的插件,其内容分别为:
libminus项目的minus.cpp文件内容如下:

extern "C" int calc(int a, int b) { return a - b; }

libmultiply项目的multiply.cpp文件内容如下:

extern "C" int calc(int a, int b) { return a * b; }

libdivide项目的divide.cpp文件内容如下:

extern "C" int calc(int a, int b) { return a / b; }

修改主项目的main.cpp文件中加载的动态库,可单独测试每一个插件是否正确运行。测试结果是通过。
接下来,我们必须在主项目中管理这些组件,然后根据用户输入的信息动态的选择应该使用的插件。一个简单的版本如下:

#include <stdio.h> #include <stdlib.h> #include <dlfcn.h> #include <assert.h> typedef int (*calc_t)(int a, int b); struct dl_mod { void* module; calc_t calc; } mod[4]; int main(int argc, char* argv[]) { for (int i = 0; i < 4; i++) { void* module = dlopen(argv[i + 1], RTLD_NOW); assert(module != NULL); calc_t calc = (calc_t) dlsym(module, "calc"); assert(calc != NULL); mod[i].module = module; mod[i].calc = calc; } do { int i_calc; printf("select the calculate number:"); scanf("%d", &i_calc); int i_first; printf("input the first number:"); scanf("%d", &i_first); int i_second; printf("input the second number:"); scanf("%d", &i_second); int i_result = (*(mod[i_calc].calc))(i_first, i_second); printf("the result is %d\n\n", i_result); } while (true); for (int i = 0; i < 4; i++) { dlclose(mod[i].module); } return 0; }

当然这个版本有一个比较要命的问题,你必须知道在命令行中输入的组件的顺序,然后才能准确调用那个组件。为了解决这个问题,我们可以给插件增加一些元数据。修改后的版本如下:
libadd项目增加如下代码:

extern "C" char* description() { return "add"; }

libminus项目增加如下代码:

extern "C" char* description() { return "minus"; }

libmultiply项目增加如下代码:

extern "C" char* description() { return "multiply"; }

libdivide项目增加如下代码:

extern "C" char* description() { return "divide"; }

主项目的代码如下:

#include <stdio.h> #include <stdlib.h> #include <dlfcn.h> #include <assert.h> typedef char* (*description_t)(); typedef int (*calc_t)(int a, int b); struct dl_mod { void* module; char* desc; calc_t calc; } mod[4]; int main(int argc, char* argv[]) { for (int i = 0; i < 4; i++) { void* module = dlopen(argv[i + 1], RTLD_NOW); assert(module != NULL); description_t desc = (description_t) dlsym(module, "description"); assert(desc != NULL); calc_t calc = (calc_t) dlsym(module, "calc"); assert(calc != NULL); mod[i].module = module; mod[i].desc = (*desc)(); mod[i].calc = calc; } do { for (int i = 0; i < 4; i++) { printf("%d:%s\n", i, mod[i].desc); } int i_calc; printf("select the calculate number:"); scanf("%d", &i_calc); int i_first; printf("input the first number:"); scanf("%d", &i_first); int i_second; printf("input the second number:"); scanf("%d", &i_second); int i_result = (*(mod[i_calc].calc))(i_first, i_second); printf("the result is %d\n\n", i_result); } while (true); for (int i = 0; i < 4; i++) { dlclose(mod[i].module); } return 0; }


运行结果如下:

./calc libadd.dylib libminus.dylib libmultiply.dylib libdivide.dylib 0:add 1:minus 2:multiply 3:divide select the calculate number:0 input the first number:3 input the second number:4 the result is 7 0:add 1:minus 2:multiply 3:divide select the calculate number:

好了,前向插件系统的设计基本已经都展示完了。当前这是一个简单的实例,简单的接口,简单的管理。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值