Single Responsibility Principle in Serialization

Years ago I programmed in Visual C++ and MFC.  Although the MFC library is functionaly rich, it broke a lot of clean code principles laying the groundwork for writing unstable code.  Somewhere alon gthe line Microsoft realized the error of their ways and came up with a cleaner architecture in the .NET framework.

So you don't think I'm just blowing smoke, let's talk about how serialization was designed in MFC.  MFC (the Microsoft Foundation Classes)  had a root element called CObject.   Mostly everything inherited from CObject in the framework.  The chief advantage of using CObject was that it had the ability to be serialized.  That means that any object that derived from CObject could override the serialize method and serialize itself.  Therefore, you would tend to come up with the pattern that every object in your design knew how to serialize itself to a stream (or in MFC land, a CArchive).

The problem with this approach, is that it breaks the Single Responsibility Principle.  Not only does your class derived from CObject have some specific purpose such as bringing up a dlialog, but it also has the knowledge of how to serialize itself.  So what is the problem with this, you might ask?  If someday you decided you didn't want to serialize your objects to a CArchive, but instead wanted to send your object to say an XML file you would have to go into every object you are serializing and rewrite the serialize method.

This of course makes absolutely no sense, but if you used the MFC CArchive approach, you would have a reached a tight coupling in your code between serialization and the class supporting it.

A better approach to serialization is to write a completely separate class (or set of classes) whose only purpose in life is to serialize your instances.  One class may know how to serialize XML, one class may know how to serialize to an Excel Spreadsheet and another class may know how to serialize to a database.   You might design a serialization interface that each of these special serializations implements so that in order to create a new serialization format, you would just add an additional class that implements that interface.  The responsibility of serialization has been completely separated from the instances it is writing (or reading). 

The .NET serializers include such serializers that separate out the responsibility of serialization.  These include XmlSerializer, BinaryFormatter, JsonDataContractSerializer, and SoapSerializer and
In the .NET approach there is a small coupling when using the serializers that are part of the libraries.  You can add attributes to the members of your class to give hints on how to serialize it.  This is somehow a little less obtrusive than the CArchive Serialization because it doesn't force you to use these attributes if you wanted to use a custom serializer to serialize something completely different.  The Serialize method in MFC takes a CArchive arguement so you are trapped into using the binary format this produces.