One problem related to composite pattern is how to implement operations over child collections. Composite classes have children and leaf classes not. There are many ways how to solve the problem of where and how to keep child nodes collection. In this posting I go through different options and analyze those solutions through different code examples.

Problem

Leaf classes in composite pattern inherit also methods and properties that are used by composite classes. Leaf classes cannot always throw exception when some composite class method is called. For some cases we need leaf classes to return similar data to one that composite class returns. How to make leaf classes behave like composite classes with not much overhead?

We will use media folder example code from my composite pattern posting and we try to add playlists support to our sample application.

As media folders may contain subfolders with media files we need something that makes also subfolder searchable through LINQ. Instead of inventing the wheel we use simple code from David Jade’s blog postUsing LINQ to Objects for recursion:

Child node collections

Now we have to decide what we will do with child node collections. There are several options:

Define child node collection in MediaItem class.

Define child node collection in composite classes.

Use empty collection with leaf classes.

Read-only collections. We will use read-only collections in public surface of media items. If we want to apply reference back to parent object then we must change the parent reference when child is moved from one parent to another. This is why we have add and remove operations as methods.

Defining child node collection in base class

If we define child collections in MediaItem class then all leaf classes have these collections too. They do nothing with these classes but still they have those classes instantiated. If we have many leaf objects then those lists just waste memory.

Defining child nodes collection in composite classes

If collctions for child nodes are defined only in composite implementations then leafs are free of collections. The question is now what should leaf classes do when GetItems() is called. We can throw exception:

But this is not good idea because then we have to check if class is leaf or not and our LINQ queries are not so generic anymore – we cannot write searches over all media items. We can also return null:

public override IEnumerable<MediaItem> GetChildren()
{
return null;
}

Now we havenew problem – our LINQ method doesn’t expect child nodes collection to be null. It just breaks. Of course, we can make the extension method more safe and ignore nulls but then we end up with hacks specific to our implementation problems.

Using empty collections with leaf classes

We can make leaf classes return empty collections when child nodes are asked:

This solution doesn’t force MediaItem to keep references to lists but creating two new objects per method call may lead to poor performance. Here is one trick we can do: we can use singleton pattern for dummy list that leaf classes return.

We define this dummy list in static scope of MediaItem class. There’s no danger of threading issues as we show this dummy class as read-only collection. There are now operations that will change the data in base collection:

Wrapping up

Dealing with child nodes collections in composite pattern needs some analysis to make good implementation decisions. In this example we made composite classes use their internal collections. Leaf classes are using static dummy list that is defined in base class. Instead of creating new empty instances in GetChildren() method we use one static readonly instance as we don’t allow direct modification of child nodes collection. Our solution is pretty good as we can also use LINQ to Objects queries over whole folder structure.