目录
1.前言
在之前讲过,写好的服务类PluginAImpl必须注册到服务中心,别的插件才能使用。
void PluginAActivator::start(ctkPluginContext* context)
{
PluginAImpl* pluginAImpl = new PluginAImpl(context);
context->registerService<PluginAService>(pluginAImpl);
m_s.reset(pluginAImpl);
}
这种写法就是插件启动就把服务PluginAImpl注册到服务中心,不管这个服务其它地方使用还是不使用。如果没有地方使用它,这个服务就处理空闲状态,浪费系统资源。那么有没有什么其它办法使用它的时候才创建呢?有,那就是服务工厂。
服务工厂其实就是懒汉式使用服务,需要的时候才去创建它。它的优点还有:
1)延迟初始化:CTK服务工厂支持服务的延迟初始化,即在实际需要服务时才创建服务对象,这有助于减少应用程序启动时的资源消耗和提高性能。
2)插件化支持:在插件化架构中,CTK服务工厂能够根据插件的元数据或请求参数为不同的插件提供不同的服务实例,增强了系统的灵活性和可扩展性。
3)服务管理:通过服务工厂,开发人员可以更方便地注册、获取和释放服务,简化了服务的管理过程。
2.实现方式
1.定义服务接口:首先定义一个或多个服务接口,这些接口包含了服务需要实现的方法。
2.实现服务接口:为每种服务实现创建具体的类,这些类实现了服务接口中定义的方法。
3.创建服务工厂:实现ctkServiceFactory
接口,在接口实现中根据插件的元数据或请求参数返回相应的服务实例。
4.注册服务工厂:在插件的激活类中,将服务工厂注册为服务,以便在需要时可以通过服务注册中心获取服务实例。
3.具体实现
以打印为例,提供三种服务,分别是:直接打印、打印后加3个点、加上时间戳打印
①接口类
PluginAService.h
#ifndef PLUGINASERVICE_H
#define PLUGINASERVICE_H
#include <QtPlugin>
class PluginAService
{
public:
virtual ~PluginAService() {}
virtual void A_Func() = 0;
};
#define PluginAService_iid "org.commontk.service.demos.PluginAService"
Q_DECLARE_INTERFACE(PluginAService, PluginAService_iid)
//此宏将当前这个接口类声明为接口,后面的一长串就是这个接口的唯一标识。
#endif // PLUGINASERVICE_H
②直接打印实现类
PluginAImpl.h
#ifndef PLUGINAIMPL_H
#define PLUGINAIMPL_H
#include "PluginAService.h"
#include <QObject>
class ctkPluginContext;
class PluginAImpl : public QObject, public PluginAService
{
Q_OBJECT
Q_INTERFACES(PluginAService)
/*
此宏与Q_DECLARE_INTERFACE宏配合使用。
Q_DECLARE_INTERFACE:声明一个接口类
Q_INTERFACES:当一个类继承这个接口类,表明需要实现这个接口类
*/
public:
PluginAImpl(ctkPluginContext* context);
void A_Func() Q_DECL_OVERRIDE;
};
#endif // PLUGINAIMPL_H
PluginAImpl.cpp
#include "PluginAImpl.h"
#include <QtDebug>
PluginAImpl::PluginAImpl(ctkPluginContext* context)
{
}
void PluginAImpl::A_Func()
{
qDebug() << "A_Func()";
}
③打印后加3个点实现类
PluginAImplD.h
#ifndef PLUGINAIMPLD_H
#define PLUGINAIMPLD_H
#include "PluginAService.h"
#include <QObject>
class ctkPluginContext;
class PluginAImplD : public QObject, public PluginAService
{
Q_OBJECT
Q_INTERFACES(PluginAService)
/*
此宏与Q_DECLARE_INTERFACE宏配合使用。
Q_DECLARE_INTERFACE:声明一个接口类
Q_INTERFACES:当一个类继承这个接口类,表明需要实现这个接口类
*/
public:
PluginAImplD(ctkPluginContext* context);
void A_Func() Q_DECL_OVERRIDE;
};
#endif // PLUGINAIMPLD_H
PluginAImplD.cpp
#include "PluginAImplD.h"
#include <QtDebug>
PluginAImplD::PluginAImplD(ctkPluginContext* context)
{
}
void PluginAImplD::A_Func()
{
qDebug() << "A_Func() ...";
}
④加上时间戳打印实现类
PluginAImplT.h
#ifndef PLUGINAIMPLT_H
#define PLUGINAIMPLT_H
#include "PluginAService.h"
#include <QObject>
class ctkPluginContext;
class PluginAImplT : public QObject, public PluginAService
{
Q_OBJECT
Q_INTERFACES(PluginAService)
/*
此宏与Q_DECLARE_INTERFACE宏配合使用。
Q_DECLARE_INTERFACE:声明一个接口类
Q_INTERFACES:当一个类继承这个接口类,表明需要实现这个接口类
*/
public:
PluginAImplT(ctkPluginContext* context);
void A_Func() Q_DECL_OVERRIDE;
};
#endif // PLUGINAIMPLT_H
PluginAImplT.cpp
#include "PluginAImplT.h"
#include <QtDebug>
#include <QTime>
PluginAImplT::PluginAImplT(ctkPluginContext* context)
{
}
void PluginAImplT::A_Func()
{
qDebug() << QTime::currentTime().toString("HH:mm:ss ") << "A_Func()";
}
⑤服务工厂类
servicefactory.h
#ifndef SERVICEFACTORY_H
#define SERVICEFACTORY_H
#include <QObject>
#include "PluginAImpl.h"
#include "PluginAImplD.h"
#include "PluginAImplT.h"
#include "ctkServiceFactory.h"
class ServiceFactory : public QObject, public ctkServiceFactory
{
Q_OBJECT
Q_INTERFACES(ctkServiceFactory)
public:
ServiceFactory();
QObject* getService(QSharedPointer<ctkPlugin> plugin, ctkServiceRegistration registration) override;
void ungetService(QSharedPointer<ctkPlugin> plugin, ctkServiceRegistration registration,QObject* service) override;
};
#endif // SERVICEFACTORY_H
servicefactory.cpp
#include "servicefactory.h"
#include "ctkPlugin.h"
#include "ctkPluginConstants.h"
#include <QDebug>
ServiceFactory::ServiceFactory()
{
}
QObject *ServiceFactory::getService(QSharedPointer<ctkPlugin> plugin, ctkServiceRegistration registration)
{
Q_UNUSED(registration)
QHash<QString,QString> headers = plugin->getHeaders();
ctkVersion version = ctkVersion::parseVersion(headers.value(ctkPluginConstants::PLUGIN_VERSION));
QString name = headers.value(ctkPluginConstants::PLUGIN_NAME);
QString symbolicName = headers.value(ctkPluginConstants::PLUGIN_SYMBOLICNAME);
Q_UNUSED(version) //暂时没使用到
Q_UNUSED(name)
QObject* obj;
if(symbolicName == "PluginAImpl")
{
obj = new PluginAImpl;
}
else if(symbolicName == "PluginAImplD")
{
obj = new PluginAImplD;
}
else
{
obj = new PluginAImplT;
}
return obj;
}
void ServiceFactory::ungetService(QSharedPointer<ctkPlugin> plugin, ctkServiceRegistration registration, QObject *service)
{
Q_UNUSED(plugin)
Q_UNUSED(registration)
Q_UNUSED(service)
}
⑥激活类
PluginAActivator.h
#ifndef PLUGINAACTIVATOR_H
#define PLUGINAACTIVATOR_H
#include <QObject>
#include "ctkPluginActivator.h"
#include "servicefactory.h"
class PluginAActivator : public QObject, public ctkPluginActivator
{
Q_OBJECT
Q_INTERFACES(ctkPluginActivator)
Q_PLUGIN_METADATA(IID "PLUGINA")
//向Qt的插件框架声明,希望将xxx插件放入到框架中。
public:
void start(ctkPluginContext* context);
void stop(ctkPluginContext* context);
private:
QSharedPointer<ServiceFactory> m_s;
};
#endif // PLUGINAACTIVATOR_H
PluginAActivator.cpp
#include "PluginAActivator.h"
#include <QDebug>
void PluginAActivator::start(ctkPluginContext* context)
{
ServiceFactory* s = new ServiceFactory;
context->registerService<PluginAService>(s);
factory.reset(s);
}
void PluginAActivator::stop(ctkPluginContext* context)
{
Q_UNUSED(context)
//Q_UNUSED,如果一个函数的有些参数没有用到、某些变量只声明不使用,但是又不想编译器、编辑器报警报,其他没有什么实际性作用
}
调用的方式,服务工厂和非服务工厂都是一样的,就不在这里赘述了。
4.注意事项
1)服务稳定性:由于服务是动态获取的,因此在使用服务时需要注意服务的稳定性,避免因服务不可用而导致的错误。
2)性能考虑:虽然延迟初始化可以提高性能,但在某些场景下,如果服务频繁被请求且初始化时间较长,可能会对性能产生影响。
3)安全性:在提供服务时,需要考虑服务的安全性,确保服务不会被恶意调用或滥用。
综上所述,CTK服务工厂是CTK框架中一个非常有用的功能,它为开发者提供了一种灵活、高效的服务管理工具,有助于构建更加模块化、可扩展和可维护的应用程序。