- 在日常业务中服务数据请求是很常见的模块,接触到的软件有太多地方需要请求数据,然而每次都是在用的时候增加数据解析和数据请求函数导致整体的源码可读性很差,通常的做法是封装get/post/put接口,然后对数据解析进一步封装,但这种封装很散,会导致不同cpp文件中可能都会散落有数据请求和数据解析。
- 最近在尝试使用策略、模板方法和工厂模式将数据请求的接口进行统一化,结合模板、多态将不同的请求封装成实现类,形成一个完整的继承体系,也不知道这个东西的实用性如何,但以此为节点将这次的优化记录起来也是一种进步,待以后有更好的方法后再回首评价。
- 工具:c++11、Qt、VS2013
//IServer.h
#pragma once
#include <string>
#include <QTimer>
#include <QNetworkReply>
#include <QNetworkRequest>
#include <QNetworkAccessManager>
using namespace std;
template<class T>
class IServerReturnMember
{
public:
IServerReturnMember(){}
virtual ~IServerReturnMember(){}
/************************************************************************/
/*@brief : 获取解析后的数据,只适用于http+get请求接口,未封装其他接口
/*@示例 :
IServerReturnMember<KeyData>* t = new KeyDistrctMember;
auto tt = t->getServerData("http://192.168.190.240:19091/warning/region?timeBackInSeconds=1000");
/************************************************************************/
T getServerData(std::string url);
/************************************************************************/
/*@brief : 数据解析接口,需要继承此类并实现此接口
/************************************************************************/
virtual void parseJson(string str) = 0;
protected:
T _data;
private:
string getServer(string url);
};
template<class T>
T IServerReturnMember<T>::getServerData(std::string url)
{
string str = getServer(url);
parseJson(str);
return _data;
}
template<class T>
string IServerReturnMember<T>::getServer(string url)
{
QTimer* timer = new QTimer;
timer->setSingleShot(true); //单次触发
timer->start(50000);
QNetworkRequest networkRequest = QNetworkRequest(QUrl(QString::fromStdString(url)));
QNetworkAccessManager* networkManager = new QNetworkAccessManager();
QNetworkReply* networkReply = networkManager->get(networkRequest);
QEventLoop eventLoop;
QObject::connect(networkReply, &QNetworkReply::finished, &eventLoop, &QEventLoop::quit);
QObject::connect(timer, SIGNAL(timeout()), &eventLoop, SLOT(quit()));
eventLoop.exec(QEventLoop::ExcludeUserInputEvents);
if (networkReply->isRunning())
{
networkReply->abort();
networkReply->deleteLater();
networkReply = nullptr;
timer->stop();
timer->deleteLater();
timer = nullptr;
networkManager->deleteLater();
networkManager = nullptr;
return "";
}
QByteArray replyData = networkReply->readAll();
networkReply->deleteLater();
networkReply = nullptr;
timer->stop();
timer->deleteLater();
timer = nullptr;
networkManager->deleteLater();
networkManager = nullptr;
return replyData;
}
以上是基类,特定数据请求需要继承IServerReturnMember,并实现数据解析接口
//特定接口请求实现类
#pragma once
#include <typeinfo>
#include "IServerData.h"
struct KeyData
{
int ie;
double de;
};
class KeyDistrctMember :public IServerReturnMember<KeyData>
{
public:
KeyDistrctMember()
{}
~KeyDistrctMember(){}
//解析数据
void parseJson(string str)
{
_data.de = 3.6;
_data.ie = 4;
return;
}
};
使用时的测试示例:
IServerReturnMember<KeyData>* t = new KeyDistrctMember;
auto tt = t->getServerData("http://192.168.190.240:19091/warning/region?timeBackInSeconds=1000");