views:

117

answers:

6

Hi all. This might be a little subjective, but I'd like to get your input on my current situation. I have a class that will be used to serialize/deserialize an object.

public class MyClass
{
    public static string ToXmlString( MyClass c ) { /*...*/ }
    public static MyClass FromXmlString( string xml ) { /*...*/ }
}

I only like this approach because it keeps the two functions at the same level. However, my goal is to avoid using static methods (when feasable). It also feels like I might be vilolating SRP, but the main goal of this object is that it can be seriliazed/deserialized from an xml string.

Any thoughts on the use of static methods in this situation? Should I just make the ToXmlString non-static, but leave the FromXmlString static? Should I create a new class that will only handle serilization of MyClass?

EDIT:

The class that I'm discussion here is a simple transfer object. It is used to save/restore values from a thrid party tool.

Thanks!

A: 

If you want a standard serialization (XML or not), both serialize/deserialize methods should not be static.

In MyClass, you should redefine "writeObject" and "readObject" to replace the default serialization methods by yours. Here is a Sun tutorial about theses methods.

If you don't want a "standard serialization", using static methods looks fine for me. Static util methods are not an heresy.

PS : it is not the question, but if you want WML serialization, you can use the XStream API.

Benoit Courtine
"real serialization"? Do you mean what Jerod has now isn't "real"? There're lots of perfectly valid reasons not to use standard serialization mechanisms.
Nikita Rybak
You are right. The "Standard" world is better than "real": I edited my post to correct that, thanks.
Benoit Courtine
+2  A: 

FWIW I think that serialization is a problematic that should be separated from the rest of your class, above all if your class is a business type.

The general rule when developing a component is to ensure that it only addresses a few concerns and to separate business concerns from technical ones.

What if later you need to manage serialization from a database or a binary format ?

You might end with more and more technical methods (SaveToDB, LoadFromDB, ToBinaryStream, FromBinaryStream...) that would clutter your class and make it more and more difficult to maintain, hiding its primary purposes (business for example).

Serious
A: 

Elaborating on Benoit's answer, here's an example where the class that is being serialized defines the serializing behavior (I did not write this):

// : c12:SerialCtl.java
// Controlling serialization by adding your own
// writeObject() and readObject() methods.
// From 'Thinking in Java, 3rd ed.' (c) Bruce Eckel 2002
// www.BruceEckel.com. See copyright notice in CopyRight.txt.

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class SerialCtl implements Serializable {
  private String a;

  private transient String b;

  public SerialCtl(String aa, String bb) {
    a = "Not Transient: " + aa;
    b = "Transient: " + bb;
  }

  public String toString() {
    return a + "\n" + b;
  }

  private void writeObject(ObjectOutputStream stream) throws IOException {
    stream.defaultWriteObject();
    stream.writeObject(b);
  }

  private void readObject(ObjectInputStream stream) throws IOException,
      ClassNotFoundException {
    stream.defaultReadObject();
    b = (String) stream.readObject();
  }

  public static void main(String[] args) throws IOException,
      ClassNotFoundException {
    SerialCtl sc = new SerialCtl("Test1", "Test2");
    System.out.println("Before:\n" + sc);
    ByteArrayOutputStream buf = new ByteArrayOutputStream();
    ObjectOutputStream o = new ObjectOutputStream(buf);
    o.writeObject(sc);
    // Now get it back:
    ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(
        buf.toByteArray()));
    SerialCtl sc2 = (SerialCtl) in.readObject();
    System.out.println("After:\n" + sc2);
  }
}

Note the use of transient to describes fields that will not be serialized.

Amir Afghani
A: 

I don't think it's too terrible for complementary methods to be separated with regard to static vs. instance, since the Framework does this occasionally (String.Split / Join, for example).

But having said that, I think the goal of minimizing the use of static methods is not a good idea. The thing to avoid is static mutable state, not static methods. A static method that only operates on its parameters, rather than static variables, is pure awesomeness.

A pure static function can be more maintainable than an instance method, since the instance method does not communicate in an obvious way which instance fields it can mutate. By following the rule that no static state whatsoever is maintained, a static method can be relied upon to only operate on its parameters, and thus the method's role in the application can be better predicted. This is especially important when multi-threading.

Since the ToXmlString method is being applied to an instance of the class in which it is defined, some of these considerations don't apply. It could easily change the state of the object that is being passed to it in underhanded ways, since it can access all the private members of the instance. But I just mean to say that as a general rule static methods are not a problem.

Jeffrey L Whitledge
A: 

You could define a constructor that takes an XMLReader (or a string if you really insist). The main advantage of this is that it allows you to have stronger invariants in your class, and to be explicit about any immutable members through the use of readonly.

Jon Hanna
+1  A: 

The convention in the standard libs for both C# and Java is that To__ methods are instance methods and From__ methods are static (by necessity). For example: ToString() is an instance method.

munificent