Composition over Inheritance: Custom Collections

Composition over inheritance is a known but unfortunately not very well understood OOD principle.

All too often I see code like this:

public class MyFooList : List<Foo> { /* .. */ }

or this:

public class MySomething
{
  public List<Foo> Foos { get; set; }
}

The derived class adds a method or two. Maybe a property. And it carries all the weight of the super-class List<T>. The property of type List<Foo> is there for anybody to fill with content of unverified qualities. Why?!

List is a powerful class but it does not give you any control over the objects that are added to it. What if your custom collection needs to protect invariants like “You can only add Foos with a Bar > 7?” Or you can only append to your collection but not remove objects from it. There is no easy way to model this when you are inheriting from List<T> or providing raw lists as part of your API.

If you don’t need the majority of the 30-some methods and the ~10 properties why would you show them? They just blur your interface. A simple custom collection that only offers what your consumers need to know is simple enough to write. If you implement IEnumerable<T> you can even unleash all the power of LINQ to select items from your collection.

If you have many or very complex invariants encapsulate them in validators to protect your collection. Let the collection tell its consumers about the rules a Foo instance violates when they are trying to add it to the collection.

[TestMethod]
public void Should_NotifyOnViolatedInvariants()
{
  var collection = new MyFooCollection(new IFooValidator[] { new NotNullValidator(), new MinBarValidator(7) });
  
  IFooValidator violatedInvariant;
  Assert.IsFalse(collection.Add(null, out violatedInvariant));
  Assert.IsInstanceOfType(violatedInvariant, typeof(NotNullValidator));

  Assert.IsFalse(collection.Add(new Foo() { Bar = 1 }, out violatedInvariant));
  Assert.IsInstanceOfType(violatedInvariant, typeof(MinBarValidator));
  Assert.IsTrue(collection.Add(new Foo { Bar = 8 }, out violatedInvariant));
}

public class MyFooCollection : IEnumerable<Foo>
{
  private readonly IEnumerable<IFooValidator> validators;
  private readonly List<Foo> foos;
  public MyFooCollection(IEnumerable<IFooValidator> validators)
  {
    this.validators = validators ?? new IFooValidator[0];
    this.foos = new List<Foo>();
  }
  public bool Add(Foo foo, out IFooValidator violatedInvariant)
  {
    violatedInvariant = this.validators.FirstOrDefault(v => v.ViolatesInvariant(foo));
    if (violatedInvariant == null)
    {
      this.foos.Add(foo);
      return true;
    }
    return false;
  }
  public IEnumerator<Foo> GetEnumerator()
  {
    return this.foos.GetEnumerator();
  }
  IEnumerator IEnumerable.GetEnumerator()
  {
    return this.GetEnumerator();
  }
}
public interface IFooValidator
{
  string Description { get; }
  bool ViolatesInvariant(Foo foo);
}
public class MinBarValidator : IFooValidator
{
  private readonly int minBar;
  public MinBarValidator(int minBar)
  {
    this.minBar = minBar;
  }
  public string Description
  {
    get { return string.Format("foo.Bar must be greater than {0}", this.minBar); }
  }
  public bool ViolatesInvariant(Foo foo)
  {
    return foo.Bar <= this.minBar;
  }
}
public class NotNullValidator : IFooValidator
{
  public string Description
  {
    get { return "foo must not be null."; }
  }
  public bool ViolatesInvariant(Foo foo)
  {
    return foo == null;
  }
}
public class Foo
{
  public int Bar { get; set; }
}

You are still using the list under the covers. But your custom collection (just a couple of lines long!) is now stream-lined to only provide the functionality that is really needed. If you expose a raw List<T> anybody can modify the contents of that list. There is no way to enforce the collections invariants. With the custom collection your intentions became clearer and you made using your API safer. Isn’t that worth the bit of extra effort?

Advertisement

Rebuttal: Composite Pattern

Oren Eini (aka Ayende Rahien) has an interesting series on his blog where he reviews the GoF Design Patterns and how they apply (or don’t) to modern software development.

As part of this series he also reviews the Composite Pattern and finishes with the following advice:

Recommendation: If your entire dataset can easily fit in memory, and it make sense, go ahead. Most of the time, you probably should stay away.

I find his conclusion somewhat limited as he only seems to take data storage/structures into account. But what about code that “does” things?

If you consider the following interface:

public interface IWriter
{
  void Write(Foo foo);
}

there may be a lot of implementations that write somewhere. Like the local file system. A database. A WCF service or any number of other targets. And what if you want to write to several of those targets and not only one? Do you want to change your code to handle a List<IWriter>? Everywhere? No? Me neither. Instead I prefer to leave my existing code that knows how to write to a single target as is and introduce a composite writer that does the job of writing to multiple targets for me.

public class CompositeWriter : IWriter
{
  private readonly List<IWriter> writers = new List<IWriter>();
  public void Write(Foo foo)
  {
    foreach(var writer in this.writers)
    {
      writer.Write(foo);
    }
  }
  public void Add(IWriter writer)
  {
    this.writers.Add(writer);
  }
}

The sample ignores validation or error handling (Does the composite ignore errors in its targets and just continues? Do the targets have to handle the errors themselves etc.). It also ignores the possible complexity of the Foo it has to write. This is where I agree with Oren. If this structure is large and you need to duplicate it for every Write() you are screwed.

I also ignore the delay that might be introduced by writing to an arbitrarily large set of targets. But you can also handle that inside the composite. Maybe you introduce timeouts for calling a single writer. Or you write a decorator that calls a writer on a background thread if that fits your needs. You can make your solution as complex or simple as you have to. The fact is: Your original code won’t know about that complexity. It just calls an implementation of your IWriter interface. I think this is what SRP is about.

You isolate the callers from the possibly complex task of calling out to multiple targets. Your composite is responsible for dealing with that complexity. And that is it’s only responsibility.

IntelliSense for custom ConfigurationSections

To be frank: I don’t like XML for configuration purposes. I think it’s a plague and nothing less. It is verbose and prone to typos. It does not give you any type safety. Thus I wage a constant war against XML config files in my projects.
But sometimes you can’t avoid XML for one reason or another. And if you can’t avoid it you have to cope with its shortcomings. Configuration in code gives you (among many other things I value) IntelliSense support. You get help with possible values for variables, properties or parameters, method names and much more. To get (some of) the same convenience for config files you have to provide xsd schema files. Established frameworks sometimes ship with those schemas. But if you write custom config sections you are completely on your own.

Rob Seder has a great post on writing custom configuration sections. The last paragraph explains how you can create xsd’s for your components.

While playing with Enumeration Classes I also wanted to see how I can use them with config files. So I wrote a custom config section for evaluation purposes.

public class MyConfigSection : ConfigurationSection
{
  private readonly ConfigurationProperty myEnum;
  public MyConfigSection()
  {
    this.myEnum = new ConfigurationProperty(
      "myEnum", 
      typeof(Numbers),
      Numbers.None,
      new EnumClassConverter<Numbers>(),
      null,
      ConfigurationPropertyOptions.IsRequired);
    this.Properties.Add(this.myEnum);
  }
  public Numbers MyEnum
  {
    get { return (Numbers)base[this.myEnum]; }
    set { base[this.myEnum] = value; }
  }
}

Numbers is an enumeration class from a prior article.

[side note] I love the way Microsoft’s engineers allow you to control how the configuration system handles your custom classes by letting you specify a TypeConverter [/side note]

I followed the steps outlined in Rob’s post and created a schema using the XML –> Create Schema option from Visual Studio. I stripped away all the fluff that belonged to the config file schema until all that was left was the part for my custom section. I then added comments and allowed values for Numbers along with some more comments. I ended up with the following xsd.

<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" 
           targetNamespace="http://tecx.codeplex.com/tecx/2012/enum"
           attributeFormDefault="unqualified"
           elementFormDefault="qualified">
  <xs:element name="mySection">
		<xs:annotation>
			<xs:documentation>This demonstrates IntelliSense for config files</xs:documentation>
		</xs:annotation>
    <xs:complexType>
      <xs:attribute name="myEnum" use="required" >
        <xs:annotation>
          <xs:documentation>Predefined set of numbers</xs:documentation>
        </xs:annotation>
        <xs:simpleType>
          <xs:restriction base="xs:string">
            <xs:enumeration value="None">
              <xs:annotation>
                <xs:documentation>NaN</xs:documentation>
              </xs:annotation>
            </xs:enumeration>
            <xs:enumeration value="One">
              <xs:annotation>
                <xs:documentation>Number 1.</xs:documentation>
              </xs:annotation>
            </xs:enumeration>
            <xs:enumeration value="Two">
              <xs:annotation>
                <xs:documentation>Number 2.</xs:documentation>
              </xs:annotation>
            </xs:enumeration>
            <xs:enumeration value="Four">
              <xs:annotation>
                <xs:documentation>Number 4.</xs:documentation>
              </xs:annotation>
            </xs:enumeration>
          </xs:restriction>
        </xs:simpleType>
      </xs:attribute>
    </xs:complexType>
  </xs:element>
</xs:schema>

That’s a lot of xml for one single property but there you are… One important thing to notice is the targetNamespace attribute in the schema element. This will be used to reference the schema in your config file.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="mySection" type="TecX.EnumClasses.Test.MyConfigSection, TecX.EnumClasses.Test"/>
  </configSections>
  <mySection myEnum="Four" xmlns="http://tecx.codeplex.com/tecx/2012/enum" />
</configuration>

The section contains a reference to the targetNamespace of your custom schema. Now you need to add the xsd to the list of schemas for your config file. VS did that automatically for me when I placed the schema file in the same folder as the config file. If your’s doesn’t you can add the schema manually. Right click in the editor window for your app.config, select Properties from the context menu and the properties view will show up. It lists a setting called Schemas where the path to the DotNetConfig.xsd will already be listed. Click the […] button and add your custom schema using the dialog that pops up.

IntelliSense for custom configuration sections

And finally Visual Studio will give you some help with the tedious task of handling configuration through XML.

On top of writing the code for the configuration section you have to put some effort into writing the schema. I would not make that investment until the API is mostly stable for the current release. But then it definitely makes sense and developers that use your components will love you for that. Its the kind of documentation that does not force them to leave their working environment, lookup something in a .chm help file or a wiki page but instead they can stay focused on their current task.