gxx_base(三) 字典
GxxDictionary : 字典类
GxxDictionaryPtr : GxxDictionary的智能指针类
GxxDictionary 是基于 key-value键值对的数据结构, 笔者也把它作为json字符串的解析利器。笔者在大部分项目中都使用到它,主要在以下几个方面用到:
1. 存储key-value键值对。
2. GxxDictionaryPtr对象作为参数在业务与业务之间传递, 并且不用关心内存的释放问题。
3. 解析json字符串和字典转换成json字符串。
4. 高频访问数据做缓存, GxxDictionary能存储所有从GxxObject类继承的派生类对象,并能自动管理它们的内存释放。
key-value键值对的使用
GxxDictionaryPtr myDic = GxxDictionary::create();
// 设置值,有两种写法
myDic->setValueForKey("程序猿", "name"); // 直接使用函数
myDic["name2"] = "程序员"; // 使用[]表达式
myDic["age"] = 25;
myDic["address"] = "北京";
// 获取值
const char* myName = myDic["name"];// 获取字符串值,写法一
const char* myName2 = myDic->szStringValueForKey("name2"); // 获取字符串值,写法二
std::string myAddress = myDic->stringValueForKey("name2"); // 获取字符串值,写法三
int myAge = myDic["age"];
myAge = myDic->intValueForKey("age");
// 判断key是否存在
if (!myDic->isKeyExist("wife"))
{
printf("没有老婆\n");
}
// 遍历
GxxValueMapPtr vmap = myDic->mapKeyValue();
GxxValueMap::Iterator pos = vmap->FirstValue();
for(; !vmap->IsLastValue(pos); vmap->NextValue(pos))
{
const char* key = pos->first;
GxxValuePtr pVal = pos->second;
const char* val = pVal->stringValue();
}
在业务之间传递参数
例如: 期末考试各科老师给学生评分
// 数学老师评分
void Fun1(GxxDictionaryPtr ptr)
{
ptr["数学"] = 99;
}
// 语文老师评分
void Fun2(GxxDictionaryPtr ptr)
{
ptr["语文"] = 98;
}
// 英语老师评分
void Fun3(GxxDictionaryPtr ptr)
{
ptr["英语"] = 97;
}
int main(int argc, _TCHAR* argv[])
{
GxxDictionaryPtr student = GxxDictionary::create();
Fun1(student);
Fun2(student);
Fun3(student);
printf("成绩汇总:\n%s\n", student->toJsonText().c_str());
getchar();
return 0;
}
输出结果如下:
成绩汇总:
{"数学":"99","英语":"97","语文":"98"}
json字符串互转
const char* jsonStr = "{\"class\":\"高三1班\",\"studentCount\":\"50\",\"teachers\":{\"语文老师\":\"张三\",\"数学老师\":\"李四\",\"英语老师\":\"王五\"}}";
GxxDictionaryPtr myDic = GxxDictionary::create();
myDic->initWithJsonText(jsonStr);
printf(myDic->toJsonText().c_str());
/* 输出结果
{"class":"高三1班","studentCount":"50","teachers":{"数学老师":"李四","英语老师":"王五","语文老师":"张三"}}
*/
printf("\n");
// 用此方法得到格式化后描述信息
printf(myDic->describe_d(0, true, false).c_str());
/* 输出结果
{
"class":"高三1班",
"studentCount":"50",
"teachers":
{
"数学老师":"李四",
"英语老师":"王五",
"语文老师":"张三"
}
}
*/
printf("\n");
作为缓存
class CStudentInfo : public GxxObject
{
GXX_CREATE_FUNC(CStudentInfo)
public:
std::string no; // 学号
std::string name; // 姓名
std::string className; // 班级
std::string address; // 地址
std::vector<std::string> favs; // 兴趣爱好
public:
void print()
{
// 打印信息
}
};
// 定义CStudentInfo的智能指针类
typedef GxxAutoPtr<CStudentInfo> CStudentInfoPtr;
void ReadyStudentsInfo(GxxDictionaryPtr studentsMap)
{
// 创建二个学生对象
CStudentInfoPtr studentPtr1 = CStudentInfo::create();
studentPtr1->no = "1001";
studentPtr1->name = "小李";
studentPtr1->className = "高三1班";
studentPtr1->address = "北京";
studentPtr1->favs.push_back("看书");
studentPtr1->favs.push_back("足球");
studentPtr1->favs.push_back("音乐");
CStudentInfoPtr studentPtr2 = CStudentInfo::create();
studentPtr2->no = "1002";
studentPtr2->name = "嘎子";
studentPtr2->className = "高三1班";
studentPtr2->address = "北京";
studentPtr2->favs.push_back("打架");
studentPtr2->favs.push_back("逃课");
studentsMap["1001"] = (GxxObjectPtr)studentPtr1;
studentsMap["1002"] = (GxxObjectPtr)studentPtr2;
}
int main(int argc, _TCHAR* argv[])
{
GxxDictionaryPtr studentsMap = GxxDictionary::create();
ReadyStudentsInfo(studentsMap);
// 调取学号为 1001同学的资料
CStudentInfoPtr infoPtr = (CStudentInfo*)studentsMap->otherValueForKey("1001");
// 打印同学的信息
infoPtr->print();
}
真实实践
笔者这3年来一直在做好旺餐饮和水吧软件设计与开发,本地数据库采用sqlite3。软件视图层,经常需要查询后台设置的相关商品类型信息和商品列表信息,大家都知道商品信息有很多属性,因此在数据库必然存在多张表的关联。 每次读取商品,势必要关联几张表来联合查询。如果每次查询数据库,那么视图层的用户体验必然会很差。 因此,笔者在数据访问层创建了2个缓存, 1个来存储已查询过的商品信息,已经缓存过的商品信息则没必要再关联查询了; 另一个来存储sql语句的查询结果,完全相同的sql语句,直接返回缓存中存在的查询结果。如果web后台更改了商品信息, 数据访问层对相应的缓存做一下刷新就ok了。GxxDictionary此时为我的工作提供了巨大的便利。
笔者对sqlite3和gxx_base的使用做了一次业务应用上的封装, 加入异常机制和事务处理、防sql注入、高频sql参数化预编译缓存、简单易用的sql查询函数和执行函数、高效的批量数据插入函数。想了解的朋友可联系我: gemeryguo@126.com