最近写代码,发现很多代码都重复的出现,只是有细微的差别,之前用一个基类来做,但是发现有些地方需要根据类型来实例化。最后我想想就改用模板来实现了,之前对C++的模板只是有耳闻,但在实际项目中确很少去用。我把使用模板的时候需要的问题记录下来。
在项目中我总是遇到要写一些单例的东西,比如读取一些经常要用到的配置信息,我需要把他存在内存里面。这个时候我通常写一个单例,但是每次我都得写同样的代码,之前我就这么算了,每次写一遍,现在想想这样做重复的工作好吗,经过这次,我把它写成一个模板,因为有好几个地方需要用到。
我的单例模板:
#ifndef TEMPLATESINGLETON
#define TEMPLATESINGLETON
/**单例模板
* @author zp
* @date 2015-04-27
*/
template<typename T>
class Singleton
{
public:
static T * getInstance()
{
static T instance;
return &instance;
}
public:
Singleton(){}
~Singleton(){}
private:
Singleton(const Singleton<T> &);
Singleton& operator=(const Singleton<T> &);
};
#endif // TEMPLATESINGLETON
单例一般要把构造函数变成私有的,但是我把这个变成私有的时候,在继承的时候总是出现问题,改成公有就没有问题。
我在代码中是这样使用的
#include "TemplateSingleton.h"
#include <QMap>
#include <QString>
class AppConfig:public Singleton<AppConfig>
{
public:
AppConfig();
~AppConfig();
public:
QString getValueByKey(const QString& key);
private:
bool loadFromAppConfigFile();
bool loadFromFile(const QString& fileName);
private:
QMap<QString,QString> mapValue;
};
#endif
//调用就像其他单例一样调用
AppConfig::getInstance()->getValueByKey(“”);
具体实现就不说了,所有的都能够这么用,我感觉这让我写了好多代码,挺方便。
后来我在程序中另外一处也用了模板。。需求是这样的,我从一个webservice中获取数据,数据格式都是统一的。
我写了一个方法来获取webservice的数据,这个方法,之前在博客上写过。只是做了一些修改。这部分代码直接从我写的代码上拿过来,因为没有涉及到数据的定义,应该没什么问题。
不知道这个方式合不合适,但是现在用了,感觉还挺好
class BmilpManagerTemplate
{
public:
BmilpManagerTemplate();
virtual ~BmilpManagerTemplate();
public:
/**
* @brief addBmilpObj 添加对象
* @param method webservice方法
* @param obj 对象
* @return
*/
static int addBmilpObj(const QString& method,const T & obj);
/**
* @brief updateBmilpObjById 通过Id更新数据
* @param method webservice方法
* @param newObj
* @return
*/
static int updateBmilpObj(const QString & method,const T & newObj);
/** 根据id得到对象信息
* @brief getBmilObjById
* @param method 方法
* @param paramStr 一般是"id"
* @param id id
* @param newObj 对象
* @return
*/
static QString getBmilObjById(const QString& method, QString paramStr, int id, T & newObj);
/**
* @brief getAllBmilpObjList 获取所有数据,不分页
* @param method
* @param param
* @param selObjList
* @return
*/
static QString getAllBmilpObjList(const QString & method,QMap<QString,QVariant> & param,QList<T*> & selObjList);
/**
* @brief getAllPageBmilpObjList 分页查询得到所有的数据
* @param method
* @param param
* @param selObjList
* @return
*/
static QString getAllPageBmilpObjList(const QString & method,QMap<QString,QVariant> & param,QList<T*> & selObjList);
/**
* @brief selectBmilpObjListPage 分页查询
* @param method
* @param param
* @param selObjList
* @param pageCount
* @param pageNo
* @return
*/
static QString getBmilpObjListPage(const QString & method,QMap<QString,QVariant> & param,QList<T*> & selObjList,int& pageCount,int & pageNo);
private:
/**
* @brief addupdateBmilpObj 添加和修改对象方法
* @param method webservice 方法
* @param obj 对象
* @param isUpdateFun 是否是更新方法
* @return
*/
static int addupdateBmilpObj(const QString & method,const T & obj,bool isUpdateFun=false);
};
#include "BmilpManagerTemplate.cpp"
// BmilpManagerTemplate.cpp文件按
template<typename T>
BmilpManagerTemplate<T>::BmilpManagerTemplate()
{
}
template<typename T>
BmilpManagerTemplate<T>::~BmilpManagerTemplate()
{
}
template<typename T>
int BmilpManagerTemplate<T>::addBmilpObj(const QString &method, const T &obj)
{
return addupdateBmilpObj(method,obj,false);
}
template<typename T>
int BmilpManagerTemplate<T>::updateBmilpObj(const QString &method, const T &newObj)
{
return addupdateBmilpObj(method,newObj,true);
}
template<typename T>
QString BmilpManagerTemplate<T>::getBmilObjById(const QString &method, QString paramStr, int id, T &newObj)
{
BmilpWebServiceData data;
QMap<QString,QVariant> param;
param.insert(paramStr,id);
QNetworkReply::NetworkError netError = WebServiceHelp::getInstance()->sendGetRequest(method,param,data);
if(netError ==QNetworkReply::NoError)
{
if(data.getCode() == WebServiceReturnCode::webServiceSuccessCode)
{
QMap<QString,QVariant> dataMap = data.getData().toMap();
newObj.fromMap(dataMap);
}
}
qDebug()<<__FILE__<<__FUNCTION__<<__LINE__<<data.getMessage();
return data.getCode();
}
template<typename T>
QString BmilpManagerTemplate<T>::getAllBmilpObjList(const QString & method,QMap<QString,QVariant> & param,QList<T*> & selObjList)
{
BmilpWebServiceData data;
QNetworkReply::NetworkError netError = WebServiceHelp::getInstance()->sendGetRequest(method,param,data);
if(netError ==QNetworkReply::NoError)
{
if(data.getCode() == WebServiceReturnCode::webServiceSuccessCode)
{
if(data.getData().type()==QVariant::List)
{
QList<QVariant> dataList = data.getData().toList();
foreach(QVariant var,dataList)
{
T* pbType = new T();
QMap<QString,QVariant> dataMap = var.toMap();
pbType->fromMap(dataMap);
selObjList.append(pbType);
}
}
}
}
qDebug()<<__FILE__<<__FUNCTION__<<__LINE__<<data.getMessage();
return data.getCode();
}
template<typename T>
QString BmilpManagerTemplate<T>::getAllPageBmilpObjList(const QString &method, QMap<QString, QVariant> ¶m, QList<T *> &selObjList)
{
QString retCode = WebServiceReturnCode::webServiceFailCode;
int pageNo = 1;
int pageCount = 0;
do
{
retCode = getBmilpObjListPage(method,param,selObjList,pageCount,pageNo);
pageNo++;
}while(pageNo<=pageCount);
qDebug()<<__FILE__<<__FUNCTION__<<__LINE__<<data.getMessage();
return retCode;
}
template<typename T>
QString BmilpManagerTemplate<T>::getBmilpObjListPage(const QString &method, QMap<QString, QVariant> ¶m, QList<T *> &selObjList, int &pageCount, int &pageNo)
{
QString retCode = WebServiceReturnCode::webServiceFailCode;
BmilpWebServiceData data;
QNetworkReply::NetworkError netError = WebServiceHelp::getInstance()->sendGetRequest(method,param,data);
if(netError ==QNetworkReply::NoError)
{
if(jsonData.getCode()==WebServiceReturnCode::webServiceSuccessCode)
{
QVariantMap dataMap = data.getData().toMap();
pageCount = dataMap.value("pageCount").toInt();
pageNo = dataMap.value("pageNo").toInt();
retCode = data.getCode();
QVariant result = dataMap.value("result");
if(result.type() == QVariant::List)
{
QList<QVariant> resultList = result.toList();
foreach(QVariant var,resultList)
{
QMap<QString,QVariant> posData = var.toMap();
T * t = new T();
t->fromMap(posData);
selObjList.append(t);
}
}
}
}
qDebug()<<__FILE__<<__FUNCTION__<<__LINE__<<data.getMessage();
return retCode;
}
template<typename T>
int BmilpManagerTemplate<T>::addupdateBmilpObj(const QString &method, const T &obj, bool isUpdateFun)
{
int id = -1;
QVariantMap param;
QMap<QString,QVariant> dataMap = obj.toMap(isUpdateFun);
QVariant var(dataMap);
QJsonDocument jsonDoc = QJsonDocument::fromVariant(var);
QByteArray ba = jsonDoc.toJson(QJsonDocument::Compact);
qDebug()<<QString::fromUtf8(ba);
BmilpWebServiceData jsonData;
QNetworkReply::NetworkError netError = WebServiceHelp::getInstance()->sendPostRequest(method,param,ba,jsonData);
if(netError==QNetworkReply::NoError)
{
if(jsonData.getCode()==WebServiceReturnCode::webServiceSuccessCode)
{
if(jsonData.getData().isValid())
{
bool OK = false;
id = jsonData.getData().toInt(&OK);
if(!OK)
{
id = -1;
}
}
}
}
qDebug()<<__FILE__<<__FUNCTION__<<__LINE__<<jsonData.getMessage();
return id;
}
看看调用的地方吧:
因为模板里面有调用t->fromMap(posData); 所以t必须实现fromMap这个方法来初始化。
我程序设计里面这个t一定是我定义的object基类继承下来的,而且在基类里我把fromMap定义成了纯虚方法。
Type表示类型,obj表示对象
BmilpManagerTemplate::addBmilpObj(method,obj);
这样做我就不用吧每次调用webservice添加,重新写一遍,只是这么调用一下就解决了。
起始添加这个函数并不能体现模板的好,因为这个方法我之前用基类的方式就可以实现。
但是查询的时候不行,因为查询的时候我不能动态的知道类型,通过模板我就可以根据不同的类型给定不同的参数。
编写模板遇到的问题。之前我直接在工程里面建立的一个类,然后把方法写好,分别写在了两个不同的文件上,声明写在了头文件上,定义写在了cpp文件上,这样程序编译的时候老是出现错误,说某某函数为未找到。后来我翻了一下书籍,找到了答案。
我采取解决的办法是在头文件最后加入#include “BmilpManagerTemplate.cpp”
然后把cpp文件从工程中移除,因为模板需要在编译的时候就知道定义,所以必须让编译器知道定义,加了这个文件,起始可以把实现写到另一个头文件中这样更好。在代码中加入
include “BmilpManagerTemplate.cpp”感觉挺别扭。加了这句话后如果没有从工程中去掉.cpp文件的话,也会报错的,因为编译器会编译cpp文件,但是这个时候它是一个模板,没有具体的类型,所以会报错。去掉后编译就通过了,因为对模板的概念什么的都不熟,所以犯了很多错,很多错报的也莫名其妙不好找,花了不少时间,在此记下来。
关于模板的问题,我想过段时间,我找本书系统的学习一下,把学习的笔记给记下来,现在只是用到哪记到哪。
很多时候我只是遇到了问题,然后去解决问题,并没有那么追根究底的去把一件事情弄得很透彻。以前怎么解决的也没有记录下来,所以遇到同样的问题。我又要做一遍原来要走的路,这样不知不觉在路上花了比别人多倍的时间。现在觉得应该把一些东西记下来,哪怕它再小。因为网络这东西谁说的准,今天本来可以查到的东西,明天就消失了。