Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

A colleague and I were brainstorming about where to put the responsibility of an object to store itself on the disk in our own file format. There are basically two choices:

  1. object.store(file)
  2. fileformatWriter.store(object)

The first one gives the responsibility of serialization on the disk to the object itself. This is similar to the approach used by python pickle.

The second groups the representation responsibility on a file format writer object. The data object is just a plain data container (eventually with additional methods not relevant for storage).

We agreed on the second methodology, because it centralizes the writing logic from generic data. We also have cases of objects implementing complex logic that need to store info while the logic is in progress. For these cases, the fileformatwriter object can be passed and used as a delegate, calling storage operations on it. With the first pattern, the complex logic object would instead accept the raw file, and implement the writing logic itself.

The first method, however, has the advantage that the object knows how to write and read itself from any file containing it, which may also be convenient.

I would like to hear your opinion before starting a rather complex refactoring.

share|improve this question
2  
Most languages have serialization features available. Are you leveraging the language's serialization? If not, why not? Why reinvent serialization? –  S.Lott Feb 24 '11 at 10:57
add comment

7 Answers

up vote 5 down vote accepted

I will prefer the latter option as it follows single responsibility principle, viz an object should do only one thing and do it well. Following SRP in your case will ensure that there is loose coupling between your core functionality and persistence mechanism, that way you can change the specifics of persistence mechanism, eg. you can persist your object as XML instead of specific file format, provide encryption, or store object over a server instead of your local machine.

share|improve this answer
    
But if you do that, you violate encapsulation, since whatever serializes the object has to know the details of its internal structure (plus, you have to expose all those details). So now, if you change the implementation, you have to change it in two places (more, if you have multiple persistence mechanisms). –  TMN Feb 24 '11 at 16:25
add comment

I would definitely decouple the persistance layer from the object. It seems logical, that the persistance layer has to be interchangeable (local file, cloud, distributed cache, database).

On the other hand, if you're using language with multi-inheritance, you can use mixin pattern, to add that persistance layer into the object, thus preserving the object.store() interface, while decoupling the persistance.

share|improve this answer
add comment

It really depends on the structure and the functions of the storage.

If for example your storage is dumb and all you have to do is to write a single instance to a separate file, there are two tasks at hand. As you cannot store "object" to any media, you need to (1) serialize it and then (2) write opaque bytes to the file.

The first task is the responsibility of the object. The second task is the responsibility of the storage. So in your terms it's something like

fileformatWriter.store(object.serialize())

or something like that. Loading the object back from the storage is trickier, as you need to determine what kind of object it was by looking at the bunch of bytes, this I'd move to a class factory method. Something like

object = Object.parse(fileformatReader.load())

This implies that serializations of different Object's play by the same rules, so that there is never an ambiguity.

share|improve this answer
add comment

Is storage a core function of the object, or is storing objects a core function of (part of) your system? If the former, have objects store themselves. If the latter, have the system store the objects.

share|improve this answer
add comment

In my opinion, it depends on the complexity of the entire application. In cases where:

  • You have multiple objects that need to be written in the same file
  • Your object to write is already fairly complex
  • You possibly will need to have multiple different formats to write an object into.

Then I suggest the second option of creating a second object.

But there are definitely times where the first option will keep things simple in the code. I also like that an object knows how to write itself out. So I typically start with this option as my primary choice unless some other factor pulls me to the second option (which ends up being a common situation).

share|improve this answer
    
why embed the knowledge of the store into the class. It doesn't make things simpler. The code written in another class to store can be exactly the same but you do not get the added complexity of mixing things –  Rune FS Feb 24 '11 at 13:09
    
@Rune, there are some cases where a class hierarchy would allow for simple polymorphic solutions when a class can store itself that would create a significant amount of complexity if you had separate objects for writing out data. –  jzd Feb 24 '11 at 14:13
    
In the case where the design and hence inheritance is flawed maybe. if you have stuck to SRP all the way and the object can be serialized then no –  Rune FS Feb 24 '11 at 14:17
    
@Rune, SRP is a nice guideline, but loose coupling is not always worth the sacrifice. Following it all the way will sometimes create very complex structures that would be better off modeled differently. –  jzd Feb 24 '11 at 14:24
add comment

You can create write(OutputStream) method where object stores himself to that stream, than you will not depend for some special file storing object and at same time when you want to save object to disk you don't need to know anything about that object. But it depends how you will use this object after and who will restore object.

share|improve this answer
add comment

I agree with the Single Responsibility Principle on this one: An object should not worry about actions outside it's direct function. If I were designing a serializing model from scratch (in an OO model), I'd create a Serializer and a SerializerOverride (names may vary).

class Serializer {
   // Constructor
   public Serializer(StorageMedium sm);

   public boolean writeObject(Object o);
   public Object readObject();
   // other write/read methods if required
}

interface SerializerOverride {
   public bytes[] serialize();
   public Object deserialize();
}

A writeObject implementation could look like:

public boolean writeObject(Object o) {
   if (o instanceof SerializerOverride) {
      writeToStorage(((SerializerOverride)o).serialize)
   }
   else {
      // Serialize normally
   }
}

This way if the object does happen to need to do something itself, it can. Most of the time it won't, though, and this kind of design also allow the object to completely disregard serialization and concentrate on what it really was designed to do.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.