目录
1) 定义:接口在CTK插件框架中通常指纯虚函数类,即只包含纯虚函数的类,用于定义插件对外提供的服务规范。接口类只声明了服务的功能,而不包含具体的实现。
2) 作用:接口作为服务的前身,定义了插件之间通信的契约。其他插件或应用程序通过接口来调用插件提供的服务,而无需关心服务的具体实现细节。
3) 示例:在CTK插件框架中,可以定义一个名为HelloService
的接口类,该类包含一个纯虚函数sayHello()
,用于输出“Hello, CTK!”的字符串。
hello_service.h
- #ifndef HELLO_SERVICE_H
- #define HELLO_SERVICE_H
-
- #include
-
- class HelloService
- {
- public:
- virtual ~HelloService() {}
- virtual void sayHello() = 0;
- };
-
- #define HelloService_iid "org.commontk.service.demos.HelloService"
- Q_DECLARE_INTERFACE(HelloService, HelloService_iid)
-
- #endif // HELLO_SERVICE_H
1) 定义:插件是实现接口类的具体类,即插件是接口的实现者。每个插件都包含了一个或多个接口的实现类,以及一个激活类(Activator),负责将插件的服务注册到CTK的服务注册中心。
2) 作用:插件是CTK插件框架中的基本构建块,它们提供了应用程序所需的具体功能。通过插件,应用程序可以动态地扩展和更新其功能,而无需修改应用程序本身的代码。
3) 示例:在上面的HelloService
接口示例中,可以编写一个名为HelloImpl
的插件实现类,该类继承自QObject
和HelloService
接口,并实现sayHello()
函数的具体逻辑。
hello_impl.h
- #ifndef HELLO_IMPL_H
- #define HELLO_IMPL_H
-
- #include "hello_service.h"
- #include
-
- class ctkPluginContext;
-
- class HelloImpl : public QObject, public HelloService
- {
- Q_OBJECT
- Q_INTERFACES(HelloService)
- public:
- HelloImpl(ctkPluginContext* context);
- void sayHello() Q_DECL_OVERRIDE;
- };
-
- #endif // HELLO_IMPL_H
hello_impl.cpp
- #include "hello_impl.h"
- #include
- #include
-
- HelloImpl::HelloImpl(ctkPluginContext* context)
- {
- context->registerService
(this); - }
-
- void HelloImpl::sayHello()
- {
- qDebug() << "Hello,CTK!";
- }
1) 定义:服务是根据接口实例化的对象,是插件向外部提供的功能单元。每个服务都对应一个接口的实现,并通过CTK的服务注册中心进行注册和发现。
2) 作用:服务是插件之间通信的桥梁。当其他插件或应用程序需要调用某个插件的功能时,它们会通过服务注册中心查找并获取相应的服务实例,然后调用该实例上的方法来执行所需的操作。
3) 示例:在CTK插件框架中,当HelloImpl
插件被加载并激活后,它会将其实现的HelloService
服务注册到服务注册中心。其他插件或应用程序可以通过服务注册中心获取HelloService
服务的实例,并调用sayHello()
方法来输出“Hello, CTK!”的字符串。
- #include
- #include
- #include
-
- #include
- #include
- #include
- #include
-
- #include "../Service/hello_service.h"
-
- int main(int argc, char *argv[])
- {
- QCoreApplication app(argc, argv);
-
- ctkPluginFrameworkFactory frameWorkFactory;
- QSharedPointer
framework = frameWorkFactory.getFramework(); - try {
- // 初始化并启动插件框架
- framework->init();
- framework->start();
- qDebug() << "CTK Plugin Framework start ...";
- } catch (const ctkPluginException &e) {
- qDebug() << "Failed to initialize the plugin framework: " << e.what();
- return -1;
- }
-
- qDebug() << "********************";
-
- // 获取插件上下文
- ctkPluginContext* context = framework->getPluginContext();
-
- // 获取插件所在位置
- QString path = QCoreApplication::applicationDirPath() + "/plugins";
-
- // 遍历路径下的所有插件
- QDirIterator itPlugin(path, QStringList() << "*.dll" << "*.so", QDir::Files);
- while (itPlugin.hasNext()) {
- QString strPlugin = itPlugin.next();
- try {
- // 安装插件
- QSharedPointer
plugin = context->installPlugin(QUrl::fromLocalFile(strPlugin)); - // 启动插件
- plugin->start(ctkPlugin::START_TRANSIENT);
- qDebug() << "Plugin start:" << QFileInfo(strPlugin).fileName();
- } catch (const ctkPluginException &e) {
- qDebug() << "Failed to start plugin" << e.what();
- return -1;
- }
- }
-
- qDebug() << "********************";
-
- // 1. 获取所有服务
- QList
refs = context->getServiceReferences(); - foreach (ctkServiceReference ref, refs) {
- if (ref) {
- HelloService* service = qobject_cast
(context->getService(ref)); - if (service != Q_NULLPTR)
- service->sayHello();
- }
- }
-
- return app.exec();
- }
1) 接口与插件:一个接口可以由一个或多个插件实现,每个插件都提供了接口的一个具体实现。插件通过实现接口来定义其对外提供的服务。
2)插件与服务:一个插件可以注册多个服务,每个服务都对应一个接口的实现。插件通过激活类将其实现的服务注册到CTK的服务注册中心,以便其他插件或应用程序进行调用。
3)服务与接口:服务是接口的具体实例,是插件之间通信的实体。服务通过接口定义的契约进行交互,确保了插件之间的松耦合和可替换性。
下面是接口、插件和服务的几种对应关系:
1对1:
1个接口类由1个具体类实现,输出1个服务和1个插件。
多对1:
1个具体类实现了2个接口类,输出2个服务和1个插件,无论想使用哪个服务最终都通过这同一个插件来实现
1对多:
1接口由2个类实现,也就是某一个问题提供了2种解决思路,输出1个服务和2个插件,通过ctkPluginConstants::SERVICE_RANKING和ctkPluginConstants::SERVICE_ID来调用不同的插件。这里虽然有两个插件,但都是被编译到同一个dll中的。
在后面的讲解中都会一一举例说明这些情况的。
综上所述,CTK插件框架中的接口、插件、服务是三个紧密相关的概念,它们共同构成了一个可扩展、可复用的应用程序架构。通过这三个概念的灵活应用,可以构建出功能丰富、易于维护的生物医学图像计算应用程序。
源码地址:octo/CTK-examples