译者注:文中提到的Generic Serializer实现代码和demo程序在我上传的资源中:
代码:http://download.csdn.net/detail/manfred2manfred/5814883
demo:http://download.csdn.net/detail/manfred2manfred/5814895
By , 11 Aug 2000
简介
MFC中的CObject和CArchive类提供了一些方法供framework进行序列化操作,但是这些方法无法对包含引用关系(cyclic references)的复杂数据结构进行序列化操作,或支持的效果很有限。
本文中所描述的GenericSerialize
和GenericDeserialize
方法为上述的情况提供了一种通用的实现机制。这些泛型方法可以处理任何同构的结构化数据(datastructure consisting of nodes having all the same type)。
为使用上述方法,程序员需要自行实现一个叫做的Accessor类,并主要完成以下工作:
- 将节点指针的类型定义(typedef)为Type;
- 声明一个CArchive类型的成员变量
ar
; - 实现成员函数
Null(),
用来返回代表空(null)的Type 值;
- 实现序列化(serializing)和解序列化(deserializing)某个对象的函数;
- 实现获取兄弟节点的函数。
接口类
template<class Access>
void GenericSerialize(const Access& a);
template<class Access>
void GenericDeserialize(const Access& a);
//The Access class must adhere to the following scheme
struct MyAccess
{
typedef MyPointerType Type;
CArchive ar;
Type Null()
{/*your code*/}
void GetNeighbors(Type current,vector< pair<Type,int/*nTyp*/> >& vecNeighbors)
const
{ /*your code */ }//GetNeighbors(Null(),.. ) must place all root elements
// into <code>vecNeighbors</code>
void SerializeThis(Type owner,Type current,int nTyp)const
{ /*your code/* }
Type DeserializeThis(Type owner,int nTyp)const
{ /*your code*/ }
void SetReference(Type owner,Type current,int nTyp)const
{ /*your code*/ }//current is an already deserialized reference of owner
};
Example A - 序列化 tree view 控件类
下列代码完成了对tree view空间的序列化工作:
void CGenericSerializeDemoView::TreeSerialize(CArchive& ar)
{
TreeAccess access(m_Tree,ar); //user defined part of serialization
if (ar.IsStoring())
{
GenericSerialize(access);//general algorithm for serialization
}
else
{
m_Tree.DeleteAllItems();
GenericDeserialize(access); //general algorithm for deserialization
ApplyItemStates(m_Tree.GetRootItem());
}
}
Accessor类的实现:
struct TreeAccess{//user part for tree ctrl serialization
TreeAccess(CTreeCtrl& rTree,CArchive& rAr):tree(rTree),ar(rAr){}
typedef HTREEITEM Type; //'Type' is a mandatory member of any Access class
#define TA_eRoot 0
#define TA_eChild 1
#define TA_eSibling 2
CTreeCtrl& tree;
CArchive& ar; //'ar' is a mandatory member of any Access class
HTREEITEM Null()const {return NULL;}
void GetNeighbors(HTREEITEM current,vector< pair<Type,int> >& vecNeighbors)
const
{
if(current==NULL){//get root items
HTREEITEM hItem= tree.GetRootItem();
if(hItem){
vecNeighbors.push_back( make_pair(hItem,TA_eRoot));
}
}else{
HTREEITEM hItem= tree.GetNextSiblingItem(current);
if(hItem){
vecNeighbors.push_back(make_pair(hItem,TA_eSibling));
}
hItem= tree.GetChildItem(current);
if(hItem){
vecNeighbors.push_back(make_pair(hItem,TA_eChild));
}
}
}
void SerializeThis(HTREEITEM owner,HTREEITEM current,int nTyp)const
{
ar << tree.GetItemText(current);
ar << tree.GetItemState(current,TVIF_STATE);
}
HTREEITEM DeserializeThis(HTREEITEM owner,int nTyp)const
{
CString strItemText;
UINT nState;
ar >> strItemText;
ar >> nState;
HTREEITEM hItem;
switch(nTyp){
case TA_eRoot: hItem= tree.InsertItem(strItemText); break;
case TA_eChild: hItem= tree.InsertItem(strItemText,owner); break;
case TA_eSibling: hItem= tree.InsertItem(strItemText,
tree.GetParentItem(owner),owner); break;
}
tree.SetItemData(hItem,nState);
return hItem;
}
void SetReference(HTREEITEM owner,HTREEITEM current,int nTyp)const
{
}
};
Example B - 序列化一个通用的关系图结构
下面的 Accessor类实现了对一个包含若干节点(node)的关系图结构的序列化,其中单个节点的定义如下:
struct Graph{
Graph(int x=0,int y=0):x(x),y(y){}
int x,y;
vector<Graph*> vecConnections;
};
Accessor定义:
struct GraphAccess{//user part for graph serialization
GraphAccess(vectorGraph& rGraph,CArchive& rAr):graph(rGraph),ar(rAr){}
typedef Graph* Type; //'Type' is a mandatory member of any Access class
vectorGraph& graph;
CArchive& ar; //'ar' is a mandatory member of any Access class
#define GA_eRoot 0
#define GA_eConnect 1
Graph* Null()const {return 0;}
void GetNeighbors(Graph* current,vector< pair<Type,int> >& vecNeighbors)const
{
if(current==NULL){//get root items
for(unsigned i=0;i<graph.size();i++){
vecNeighbors.push_back( make_pair(graph[i],GA_eRoot));
}
}else{
for(unsigned i=0;i<current->vecConnections.size();i++){
vecNeighbors.push_back( make_pair(graph[i],GA_eConnect));
}
}
}
void SerializeThis(Graph* owner,Graph* current,int nTyp)const
{
ar << current->x;
ar << current->y;
}
Graph* DeserializeThis(Graph* owner,int nTyp)const
{
int x,y;
ar >> x;
ar >> y;
graph.push_back(new Graph(x,y));
return graph[graph.size()-1];
}
void SetReference(Graph* owner,Graph* current,int nTyp)const
{
if(owner!=0 && nTyp==GA_eConnect){
owner->vecConnections.push_back(current);
}
}
};