Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Requiring interface implementations to have a static Parse method

I've got a minimal interface, and will be dealing with a collection of objects whose classes implement this interface. The collection (along with its associated functionality) doesn't care about any of the details of these objects beyond their name, the ability to convert them to XML, and the ability to parse them from XML.

Future implementations of the interface will do a lot more with the elements of the collection, and will obviously implement their own Parse and ToXml methods (which will be used by the collection to parse these items appropriately when encountered).

Unfortunately, I am unable to list a static Parse method in the interface (I've read these three questions). It doesn't make sense to me to have a Parse method require an instance. Is there any way to require that all implementations of the interface have a static Parse method?

public interface IFoo
{
  string Name { get; }

  string ToXml();

  static IFoo Parse(string xml); // Not allowed - any alternatives?
}
like image 439
yoozer8 Avatar asked Mar 20 '13 14:03

yoozer8


4 Answers

You can't do that. And static methods aren't polymorphic anyway, so it wouldn't make too much sense.

What you want here is some kind of factory pattern.

like image 88
Daniel Hilgarth Avatar answered Sep 22 '22 07:09

Daniel Hilgarth


Assuming Parse takes a string and turns it into a fully-populated object, how about a Hydrate method instead, like:

interface IFoo {
    string Name { get; set; }
    int Age { get; set; }
    void Hydrate(string xml);
}

class Foo : IFoo {
    public string Name { get; set; }
    public int Age { get; set; }

    public void Hydrate(string xml) {
        var xmlReader = ...etc...;
        Name = xmlReader.Read(...whatever...);
        ...etc...;
        Age = xmlReader.Read(...whatever...);
    }
}

void Main() {
    IFoo f = new Foo();
    f.Hydrate(someXml);
}

Or Fluent it up a bit:

public IFoo Hydrate(string xml) {
    // do the same stuff
    return this;
}

void Main() {
    IFoo f = new Foo().Hydrate(someXml);
}
like image 36
Joe Enos Avatar answered Sep 21 '22 07:09

Joe Enos


The only alternative that comes to my mind is to use an abstract class instead of an interface here. However you won't be able to override static method's behaviour in child classes anyway.

You can achieve somewhat similar behaviour using Factory pattern and requiring classes implementing IFoo to have a reference to that Factory (which can be injected in them via constructor injection):

public interface IFoo
{
    string Name { get; }

    string ToXml();

    IFooFactory FooFactory { get; }
}

public interface IFooFactory
{
    IFoo Parse(string xml);
}
like image 30
Alexander Tsvetkov Avatar answered Sep 23 '22 07:09

Alexander Tsvetkov


I would extract all serialization-related methods into a different interface. Please consider the following example:

public interface IFoo
{
    string Name { get; }
    IFooSerializer GetSerializer(string format);
}

public enum FooSerializerFormat { Xml, Json };

public interface IFooSerializer
{
    string Serialize(IFoo foo);
    IFoo Deserialize(string xml);
}

public class Foo : IFoo
{
    public string Name { get; }

    public IFooSerializer GetSerializer(FooSerializerFormat format)
    {
        case FooSerializerFormat.Xml:
            return new FooXmlSerializer();

        case FooSerializerFormat.Json:
            return new FooJsonSerializer();
    }
}

public class FooXmlSerializer : IFooSerializer { /* Code omitted. */ }
public class FooJsonSerializer : IFooSerializer { /* Code omitted. */ }
like image 34
npclaudiu Avatar answered Sep 19 '22 07:09

npclaudiu