Sergey Shishkin

on agile software development

Fluent Interface and Inheritance

While writing the fluent XML writer I got confused about how to make the MemoryXmlWriter class having a really fluent interface. The MemoryXmlWriter inherits all the XML-related methods from the base FluentXmlWriter class and provides additional methods for working with its internal MemoryStream. The problem arises when any base method is called on an inherited instance and an instance of the base class is returned. There is no more way to call methods of the inherited class fluently.

A reasonable workaround for a C# developer would be to use generics to parameterize the type of the instance returned out of the base methods. But I also want to hide generics from clients because all those "<T>" constructs make code to look overcomplicated garbage. And of course, I want both the base class and the inherited class to have a common non-generic base type for polymorphic usage. Let’s look what C# can do about it. I use the foo-bar notation here instead of my XmlWriters for the sake of simplicity:

public interface IFoo
{
    IFoo DoFoo();
}

public abstract class Foo<TThis> : IFoo
    where TThis : Foo<TThis>
{
    public TThis DoFoo()
    {
        Console.WriteLine("Foo");
        return (TThis)this;
    }

    IFoo IFoo.DoFoo()
    {
        return this.DoFoo();
    }
}

public class Foo : Foo<Foo> { }

public class Bar : Foo<Bar>
{
    public Bar DoBar()
    {
        Console.WriteLine("Bar");
        return this;
    }
}

Now one can use the IFoo interface for polymorphism. The concrete Foo class turns out to be extra simple in the sample. In reality it may also have to define some constructors. An instance of the Bar class can be used to get access to the extended functionality and to the IFoo‘s methods at the same time:

IFoo f = new Foo();
f.DoFoo().DoFoo();

Bar b = new Bar();
b.DoFoo().DoBar().DoFoo().DoBar();

From the user’s perspective I like this code, because now the DoFoo() method on the Bar instance returns me back the same instance of the same Bar class instead of its base class or interface. But what was the price of that? Now I got an interface which I did not required, I have to implement the interface explicitly because I also need the same method to return the type parameter. In the end of the day I have one declaration and two implementation to maintain for each single method I want my FluentXmlWriter to have. Also, the implementation is buried inside of the cluttered infrastructure Foo<T> class, making code generation difficult.

But this is in C#. What about VB.NET and its explicit interface mapping? Things remain the same there since the return type of the implementing method must be the same as that of the declaring method.

Let’s try to simplify the previous sample:

public class Foo
{
    public Foo DoFoo()
    {
        Console.WriteLine("Foo");
        return this;
    }
}

public abstract class Foo<TThis> : Foo
    where TThis : Foo<TThis>
{
    public new TThis DoFoo()
    {
        return (TThis)base.DoFoo();
    }
}

public class Bar
    : Foo<Bar>
{
    public Bar DoBar()
    {
        Console.WriteLine("Bar");
        return this;
    }
}

Now I got rid of the IFoo interface and moved the concrete Foo class on top of the class hierarchy. The Foo class became completely unaware of the others. Moreover, the generic abstract Foo<T> class can now be 100% auto generated by a tool. Not bad 🙂

Technorati Tags:
Advertisements

Written by Sergey Shishkin

04.03.2008 at 09:53

Posted in Development

%d bloggers like this: