Should an object be written to a file, or should another object act on it to perform I / O?

NOTE. Sorry for the long question!

I am trying to understand some of the key areas behind object orientation, and I could not somehow solve my specific question.

Say I have an object full of beautiful data. Class bob.

Bob myBob = new Bob("This string is data"); 

Let's say I want to save the contents of myBob in an xml file (bob.xml)

Do I have to force the object to act on bob to write the content, or do I need myBob to do this?

Case 1: action on an object

 Writer myWriter = new Writer(myBob, "C:\\bob.xml"); 

Case 2: Save Method

 myBob.Save("C:\\bob.xml"); 

Some people support one option, as this means that if the code for writing files has been changed, it does not need to update each Save method; I assume that code reuse will happen again. My problem is getting all the data from objects that may have personal data without access.

The case for the second option is that the method acts only on the data stored in the object, and how it should be. No interference from other objects.

Or is the answer to my question one of those questions that depend on the case? If so, how do you know when one method is preferable to another?

+44
c # oop design-patterns io
May 23 '09 at 1:47 p.m.
source share
7 answers

The correct approach, in general, is your example 1. This is not responsible for the class (no matter what it does), without associating it with a specific save mechanism (disk).

You are looking at a specific case of a more generalized problem: Serialization. Good and good, if an object has any means to indicate how it should be serialized - this is the only entity that knows what it takes to deserialize. But if you make an object saved to disk, you tightly linked this object to a specific implementation.

Instead, consider creating an interface that a generic "writer" can use to "serialize" an object, regardless of what the script serializes. Thus, you can serialize to disk, to the network, to memory, to what you really need to serialize. :)

+35
May 23 '09 at 13:54
source share

I would have made Bob know how to serialize himself, since he has personal data. Another object (like your Writer ) would take this and put it on disk. Bob knows how to better handle his data, but he does not need to worry about how and where it is stored. Your Writer knows how to save data better, but you don’t have to worry about how this data is created.

+24
May 23 '09 at 13:52
source share

This is an example of how you can use the Strategy Development Template . Your myBob object may have an instance of the class that will write it. You may want the author to implement an interface or be derived from an abstract class, so the save procedure can be easily changed.
Today you save in xml, but you may need to end up storing the object in the database. This template allows you to easily change the save procedure. You will even have the opportunity to change the way you save at runtime.

+9
May 23 '09 at 14:15
source share

I preferred option 2; however, since I started really trying to understand and model the areas I'm working on, I prefer option 1.

Imagine your modeling vehicles. Why did the car know how to persist? He may know how to move, how to start and how to stop, but what is β€œSave” in the context of a vehicle.

+3
May 23 '09 at
source share

Another way is to use a visitor template. Let your object contain an Accept method that goes through the members you want to process / serialize, and so that the visitor is your serializer. Whenever you update or change serialization (plain text in xml for binary), you do not need to update the object.

We had good impressions at work, making it so. It is quite powerful.

+3
May 23 '09 at 19:05
source share

I think the correct approach is case 1, but your class can be defined in such a way as to use both approaches:

 class Bob { IWriter _myWriter = null; public Bob(){ // This instance could be injected or you may use a factory // Note the initialization logic is here and not in Save method _myWriter = new Writer("c://bob.xml") } //... public void Save(){ _myWriter.Write(this); } // Or... public void Save(string where){ _myWriter.Write(this, where); } //... } 

This can be easily changed to put the write logic and initialization in the base class so that the Bob class is even more clean and independent of storage.

-2
May 23 '09 at 2:10
source share

Do it:

 public interface Writable { public void Save(Writer w); } public interface Writer { public void WriteTag(String tag, String cdata); } public class Bob : Writable { private String ssn = "123-23-1234"; public void Save(Writer w) { w.WriteTag("ssn", ssn); } } public class XmlWriter : Writer { public XmlWriter(Sting filename) {...} public void WriteTag(String tag, Sting cdata) {...} } 

Obviously, this is not a complete solution, but you should get a general idea.

-2
May 23 '09 at 14:32
source share



All Articles