要求接口实现具有静态Parse方法

本文关键字:静态 Parse 方法 接口 实现 | 更新日期: 2023-09-27 18:04:58

我得到了一个最小的接口,并且将处理一个对象集合,这些对象的类实现了这个接口。集合(及其相关的功能)不关心这些对象的任何细节,除了它们的名称、将它们转换为XML的能力以及从XML解析它们的能力。

接口的未来实现将对集合的元素做更多的工作,并且显然将实现它们自己的Parse和ToXml方法(集合将在遇到这些项时使用它们来适当地解析这些项)。

不幸的是,我无法在接口中列出静态Parse方法(我已经阅读了这三个问题)。对我来说,让Parse方法需要实例是没有意义的。有没有办法要求接口的所有实现都有一个静态Parse方法?

public interface IFoo
{
  string Name { get; }
  string ToXml();
  static IFoo Parse(string xml); // Not allowed - any alternatives?
}

要求接口实现具有静态Parse方法

你不能那样做。而且静态方法不是多态的,所以它不会有太大的意义。

这里你需要的是某种工厂模式

假设Parse接受字符串并将其转换为完整填充的对象,那么Hydrate方法如何代替,如:

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);
}

或者流畅一点:

public IFoo Hydrate(string xml) {
    // do the same stuff
    return this;
}
void Main() {
    IFoo f = new Foo().Hydrate(someXml);
}

我想到的唯一替代方法是在这里使用抽象类而不是接口。但是,无论如何,您都无法在子类中重写静态方法的行为。

您可以使用工厂模式实现类似的行为,并要求实现IFoo的类有对该工厂的引用(可以通过构造函数注入):

public interface IFoo
{
    string Name { get; }
    string ToXml();
    IFooFactory FooFactory { get; }
}
public interface IFooFactory
{
    IFoo Parse(string xml);
}

我将把所有与序列化相关的方法提取到不同的接口中。请考虑下面的例子:

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. */ }

也许这样?

public interface IFoo
{
  string Name { get; }
  string ToXml();
  IFoo Parse(string xml);
}
public abstract class AFoo : IFoo
{
  public string Name { get; set; }
  public string ToXml() { };
  public IFoo Parse(string xml) { return AFoo.StaticParse(xml); };
  public static IFoo StaticParse(string xml) { };  // implement one here
}

即使上面可能是一个解决方案,我也会鼓励你使用抽象工厂和/或模板方法。请参阅模板方法模式。如果您不想在多个实现中共享扩展方法,另一个选择可能是使用它。

一般来说,我已经知道(偶尔)使用扩展方法做这样的事情:

public interface IFoo
{
    string Name {get;}
    string ToXml();    
}
public class Foo : IFoo
{
    public Foo(string name)
    {
        Name = name;
    }
    public string Name {get; private set;}
    public string ToXml()
    {
        return "<derp/>";
    }
}

这就是实例的内容,让我们来处理"static"位:

public static class FooExts
{
    public static IFoo Parse(this string xml)
    {
        return new Foo("derp");
    }
}

和一个测试:

void Main()
{
    var aFoo = "some xml".Parse();
    Console.WriteLine(aFoo.ToXml());
}

正如@Jim所提到的,在某些情况下,您不希望返回 Foo,在这种情况下,您可以使用以下命令:

public static T Parse<T>(
    this string xml, 
    Func<string, IFoo> useMeUseMe = null) 
    where T:IFoo
{
    if(useMeUseMe == null)
        useMeUseMe = (x => new Foo(x));
    return (T)useMeUseMe("derp");
}

唉,当我们偏离"规范"时,我们必须告诉方法我们想要什么:

var aFoo = "some xml".Parse<Foo>();
Console.WriteLine(aFoo.ToXml());    
var aBar = "some xml".Parse<Bar>(s => new Bar(s));
Console.WriteLine(aBar.ToXml());