CTK框架(二): 接口、插件和服务

时间:2024-07-16 06:57:28

Qt 插件机制使用及原理_qt插件机制-****博客

目录

1.接口(interface)

2.插件(Plugin)

3.服务(Service)

4.接口、插件、服务之间的关系

5.总结


1.接口(interface)

1) 定义:接口在CTK插件框架中通常指纯虚函数类,即只包含纯虚函数的类,用于定义插件对外提供的服务规范。接口类只声明了服务的功能,而不包含具体的实现。

2) 作用:接口作为服务的前身,定义了插件之间通信的契约。其他插件或应用程序通过接口来调用插件提供的服务,而无需关心服务的具体实现细节。

3) 示例:在CTK插件框架中,可以定义一个名为HelloService的接口类,该类包含一个纯虚函数sayHello(),用于输出“Hello, CTK!”的字符串。

hello_service.h

#ifndef HELLO_SERVICE_H
#define HELLO_SERVICE_H

#include <QtPlugin>

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

2.插件(Plugin)

1) 定义:插件是实现接口类的具体类,即插件是接口的实现者。每个插件都包含了一个或多个接口的实现类,以及一个激活类(Activator),负责将插件的服务注册到CTK的服务注册中心。

2) 作用:插件是CTK插件框架中的基本构建块,它们提供了应用程序所需的具体功能。通过插件,应用程序可以动态地扩展和更新其功能,而无需修改应用程序本身的代码。

3) 示例:在上面的HelloService接口示例中,可以编写一个名为HelloImpl的插件实现类,该类继承自QObjectHelloService接口,并实现sayHello()函数的具体逻辑。

hello_impl.h

#ifndef HELLO_IMPL_H
#define HELLO_IMPL_H

#include "hello_service.h"
#include <QObject>

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 <ctkPluginContext.h>
#include <QtDebug>

HelloImpl::HelloImpl(ctkPluginContext* context)
{
    context->registerService<HelloService>(this);
}

void HelloImpl::sayHello()
{
    qDebug() << "Hello,CTK!";
}

3.服务(Service)

1) 定义:服务是根据接口实例化的对象,是插件向外部提供的功能单元。每个服务都对应一个接口的实现,并通过CTK的服务注册中心进行注册和发现。

2) 作用:服务是插件之间通信的桥梁。当其他插件或应用程序需要调用某个插件的功能时,它们会通过服务注册中心查找并获取相应的服务实例,然后调用该实例上的方法来执行所需的操作。

3) 示例:在CTK插件框架中,当HelloImpl插件被加载并激活后,它会将其实现的HelloService服务注册到服务注册中心。其他插件或应用程序可以通过服务注册中心获取HelloService服务的实例,并调用sayHello()方法来输出“Hello, CTK!”的字符串。

#include <QCoreApplication>
#include <QDirIterator>
#include <QtDebug>

#include <ctkPluginFrameworkFactory.h>
#include <ctkPluginFramework.h>
#include <ctkPluginException.h>
#include <ctkPluginContext.h>

#include "../Service/hello_service.h"

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);

    ctkPluginFrameworkFactory frameWorkFactory;
    QSharedPointer<ctkPluginFramework> 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<ctkPlugin> 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<ctkServiceReference> refs = context->getServiceReferences<HelloService>();
    foreach (ctkServiceReference ref, refs) {
        if (ref) {
            HelloService* service = qobject_cast<HelloService*>(context->getService(ref));
            if (service != Q_NULLPTR)
                service->sayHello();
        }
    }

    return app.exec();
}

4.接口、插件、服务之间的关系

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中的。

        在后面的讲解中都会一一举例说明这些情况的。

5.总结

        综上所述,CTK插件框架中的接口、插件、服务是三个紧密相关的概念,它们共同构成了一个可扩展、可复用的应用程序架构。通过这三个概念的灵活应用,可以构建出功能丰富、易于维护的生物医学图像计算应用程序。

源码地址octo/CTK-examples

相关文章