系列化入门读物---PART2

系列化入门读物---PART2 

系列化入门 读物

这个指南描述如何轻松地系列化一个简单的对象。

这篇文章包含三个部分。

PART1  介绍基本的系列化

PART2  解释如何有效地读取无效数据和支持版本。

PART3  描述如何对复杂的对象进行系列化。

  系列化入门 读物 - PART2

Part 1 中我们看到了如何通 Carchive 并利 serialize() 方法对简单的对象进行系列化,其代码如下:

int CFoo::serialize (CArchive* pArchive) { int nStatus = SUCCESS; // Serialize the object ... ASSERT (pArchive != NULL); TRY { if (pArchive->IsStoring()) { // Write employee name and id (*pArchive) << m_strName; (*pArchive) << m_nId; } else { // Read employee name and id (*pArchive) >> m_strName; (*pArchive) >> m_nId; } } CATCH_ALL (pException) { nStatus = ERROR; } END_CATCH_ALL return (nStatus); }

这段代码有一个问题,就是当我们进行访问的数据并不是我们预期的?如果这个文件中的数据并不是一个 Cstring 并在其后跟着一个 int ,我们的 serialize() 方法将会出错。但这个还好,如果你认可错误并返回一个指定的状态如 INVALID_DATAFILE 。我们可以通过对象中的标志来来检查我们访问的是否是有效的文件。

Object signatures (对象标志)

对象标志实际上是一个用来识别对象的字符串。我们在 Cfoo 中加入一个标志:

   

  class CFoo

  {

    ...

 

    // Methods

    public:

      ...

      CString getSignature();

 

    // Data members

      ...

    protected:

      static const CString  Signature;  // object signature

  };

  // Static constants

  const CString CFoo::Signature = "FooObject";
 

下一步我们把 serialize() 修改成在系列化对象的数据成员时先对标志进行系列化。如果发现一个无效的标志或者没有发现标志,表示我们正在尝试读一个并不包含 Cfoo 对象的文件。下面是读取一个带标志的对象的逻辑图:

 

下面是代码:

int CFoo::serialize

    (CArchive* pArchive)

  {

    int nStatus = SUCCESS;

    bool bSignatureRead = false;

 

    // Serialize the object ...

    ASSERT (pArchive != NULL);

    TRY

    {

      if (pArchive->IsStoring()) {

         // Write signature

         (*pArchive) << getSignature();

 

         // Write employee name and id

         (*pArchive) << m_strName;

         (*pArchive) << m_nId;

      }

      else {

         // Read signature - complain if invalid

         CString strSignature;

         (*pArchive) >> strSignature;

         bSignatureRead = true;

         if (strSignature.Compare (getSignature()) != 0) {

            return (INVALID_DATAFILE);

         }

 

         // Read employee name and id

         (*pArchive) >> m_strName;

         (*pArchive) >> m_nId;

      }

    }

    CATCH_ALL (pException)

    {

      nStatus = bSignatureRead ? ERROR : INVALID_DATAFILE;

    }

    END_CATCH_ALL

 

    return (nStatus);

  }
 

你需要保证你的所有对象都有相同的标志,实际标志是什么并不是很重要。如果你开发一组产品进,使用相近的对像标志将对你很有帮助。另外,开发者不要误解为对不同的对象也使用相同的标志。如果你要使你的数据文件很难做回逆设计,你需你使用与对象名字没有明显联系的标志。

Versioning (版本)

在产品的生命周期你要对其进行更新,你可能会发现你必需对 CFOO 的进行添加或删除成员。如果你完全发行一个 Cfoo 新的版,当尝试对旧的版本的对象进行存取时将会失败。这个是明显不能接受的。任何一个新版的 Cfoo 必需可以对其以前版本的对象进行系列化,换名话说,就是 Cfoo serialize() 方法要可以对以前的可兼容的版本进行操作。我们很容易就可以实现对象的版本化,正如我们对对象加入一个标志一样,我们加入一个整型常量来表示版本号。

class CFoo

  {

    ...

 

    // Methods

    public:

      ...

      CString getSignature();

      int     getVersion();

 

    // Data members

      ...

    protected:

      static const CString  Signature;  // object signature

      static const int      Version;    // object version

  };
 

对象版本在 Foo.cpp 中进行定义。



// Static constants

  const CString CFoo::Signature = "FooObject";

  const int     CFoo::Version = 
 

下一步,我们把对版本的系列化加入到标志系列化之后且在成员数据系列化之前。如果遇到新的版本或者读取一个不支持的版本,在这些情况下,我们简单地返回 UNSUPPORTED_VERSION 状态。

   int CFoo::serialize (CArchive* pArchive) { int nStatus = SUCCESS; bool bSignatureRead = false; bool bVersionRead = false; // Serialize the object ... ASSERT (pArchive != NULL); TRY { if (pArchive->IsStoring()) { // Write signature and version (*pArchive) << getSignature(); (*pArchive) << getVersion(); // Write employee name and id (*pArchive) << m_strName; (*pArchive) << m_nId; } else { // Read signature - complain if invalid CString strSignature; (*pArchive) >> strSignature; bSignatureRead = true; if (strSignature.Compare (getSignature()) != 0) { return (INVALID_DATAFILE); } // Read version - complain if unsupported int nVersion; (*pArchive) >> nVersion; bVersionRead = true; if (nVersion > getVersion()) { return (UNSUPPORTED_VERSION); } // Read employee name and id (*pArchive) >> m_strName; (*pArchive) >> m_nId; } } CATCH_ALL (pException) { nStatus = bSignatureRead && bVersionRead ? ERROR : INVALID_DATAFILE; } END_CATCH_ALL return (nStatus); }

在版本 1 中我们的 Cfoo 包含两个数据成员( m_strName m_nId )。如果我们在版本 2 中加入第三个成员( int m_nDept ),我们需要决定在读取旧版本时 m_nDept 初始化成什么值。在这个例子中,我们初始化为 -1 ,这意味着职工的部门代码是未知的。

class CFoo { ... // Data members public: CString m_strName; // employee name int m_nId; // employee id int m_nDept; // department code (-1 = unknown) };

我们同样需要在 Foo.cpp 中加入版本标志并设为 2

const     int    CFoo::Version =  2   ; 


最后,我们需要修改 serialize() 中的读取数据部分,因为当读取旧版本时我们要对 m_nDept 进行初始化。注意文件保存时始终保存为最新版的。

int CFoo::serialize

    (CArchive* pArchive)

  {

    ...

    // Serialize the object ...

    ASSERT (pArchive != NULL);

    TRY

    {

      if (pArchive->IsStoring()) {

         ...

         // Write employee name, id and department code

         (*pArchive) << m_strName;

         (*pArchive) << m_nId;

         (*pArchive) << m_nDept;

      }

      else {

         ...

         // Read employee name and id

         (*pArchive) >> m_strName;

         (*pArchive) >> m_nId;

 

         // Read department code (new in version 2)

         if (nVersion >= 2) {

            (*pArchive) >> m_nDept;

         }

         else {

            m_nDept = -1; // unknown

         }

      }

    }

    CATCH_ALL (pException)

    {

      nStatus = bSignatureRead && bVersionRead ? ERROR : INVALID_DATAFILE;

    }

    END_CATCH_ALL

 

    return (nStatus);

  }
 

 

你可能感兴趣的:(object,null,Class,产品,methods,Constants)