In the last post of the series, we took a look at the Observer pattern. This time we’re going to explore the Composite pattern. The Composite pattern gives us the ability to take a complex procedure that may involve many steps and turn it into something that is simple for consumers to use.

The classic definition of the Composite pattern involves three pieces: Component, Leaf, and Composite Component. The component defines the interface that the units (leaves and\or composite components) must implement. A leaf is an implementation of a component that performs work. The composite component also implements the component interface but that’s where the similarities end. Under the covers, it contains a collection of components which could be leaves on nested composites. When an interface method is called, it delegates the call to it’s child components. This may sound more complicated than it actually is. Let’s take a look at an example to see how this could work.

C# Example

In this example, we’re going to take the process of changing a car’s oil and break it down to a group of independent tasks. Following our definition above, let’s define an IComponent interface. Per the contract of this interface, all of our “task” objects will need to include a PerformTask() method.

 
public interface IComponent
{
    void PerformTask();
}

Next, we’re going to create a base class for the tasks that are made up of a collection of child tasks. Notice that although it implements the PerformTask() method of the IComponent interface, it actually delegates the work to it’s child components.

 
public abstract class CompositeComponent : IComponent
{
    private IList<IComponent> _tasks = new List<IComponent>();

    public void PerformTask()
    {
        foreach (var task in _tasks)
            task.PerformTask();
    }

    public void AddTask(IComponent task)
    {
        _tasks.Add(task);
    }

    public void RemoveTask(IComponent task)
    {
        _tasks.Remove(task);
    }
}

Now let’s create our first needed task (aka. leaf). This one represents the draining of the old oil in the vehicle.

 
public class DrainOldOilTask : IComponent
{
    public void PerformTask()
    {
        Console.WriteLine("Draining old oil.");
    }
}

The next step is to replace the oil filter which is made of two steps, removing the old filter and installing the new one. To demonstrate this, we’ll create a new CompositeComponent subclass.

 
public class RemoveOldFilterTask : IComponent
{
    public void PerformTask()
    {
        Console.WriteLine("Removing old filter.");
    }
}

public class InstallNewFilterTask : IComponent
{
    public void PerformTask()
    {
        Console.WriteLine("Installing new filter.");
    }
}

public class ReplaceFilterTask : CompositeComponent
{
    public ReplaceFilterTask()
    {
        AddTask(new RemoveOldFilterTask());
        AddTask(new InstallNewFilterTask());
    }
}

Last, we need to create a task for adding the new oil as well as a composite “ChangeOil” task that ties it all together. Notice that the ChangeOil object is composed of both regular tasks (DrainOilTask and AddNewOilTask) as well as a composite task (ReplaceFilterTask).

 
public class AddNewOilTask : IComponent
{
    public void PerformTask()
    {
        Console.WriteLine("Adding new oil.");
    }
}

public class ChangeOil : CompositeComponent
{
    public ChangeOil()
    {
        AddTask(new DrainOldOilTask());
        AddTask(new ReplaceFilterTask());
        AddTask(new AddNewOilTask());
    }
}

Now the entire process is a simple method call.

 
new ChangeOil().PerformTask();

Output
Draining old oil.
Removing old filter.
Installing new filter.
Adding new oil.

Ruby Example

With Ruby, we no longer need to define a component interface. We just need ensure that our classes define a perform_work() method. We will, however, want to create a base class for our composite components.

 
class CompositeComponent
  def initialize
    @tasks = []
  end

  def perform_task
    @tasks.each {|task| task.perform_task}
  end

  def add_task(task)
    @tasks << task
  end

  def remove_task(task)
    @tasks.delete task
  end
end

Now we’ll create our task objects. Besides basic syntax, the structure of these classes are pretty much the same C# versions.

 
class DrainOldOilTask
  def perform_task
    puts "Draining old oil."
  end
end

class RemoveOldFilterTask
  def perform_task
    puts "Removing old filter."
  end
end

class InstallNewFilterTask
  def perform_task
    puts "Installing new filter."
  end
end

class ReplaceFilterTask < CompositeComponent
   def initialize
     super
     add_task RemoveOldFilterTask.new
     add_task InstallNewFilterTask.new
   end
end

class AddNewOilTask
  def perform_task
    puts "Adding new oil."
  end
end

class ChangeOil < CompositeComponent
   def initialize
     super
     add_task DrainOldOilTask.new
     add_task ReplaceFilterTask.new
     add_task AddNewOilTask.new
   end
end

Using the objects is also very much the same.

 
ChangeOil.new.perform_task

Output
Draining old oil.
Removing old filter.
Installing new filter.
Adding new oil.

As you can see, implementing the pattern in the two languages is pretty similar. The biggest difference is the lack of need for a component interface within the Ruby example.

Next time, we’ll be looking at the Iterator pattern. Stay tuned!

kick it on DotNetKicks.com