🎉 Hooray! After 3 years of work, I've finally released the ebook on design patterns! Check it out »

C#: Composite

Composite

Composite is a structural design pattern that allows composing objects into a tree-like structure and work with the it as if it was a singular object.

Composite became a pretty popular solution for the most problems that require building a tree structure. Composite’s great feature is the ability to run methods recursively over the whole tree structure and sum up the results.

Learn more about Composite

Application of the pattern in C#

Complexity:

Popularity:

Usage examples: The Composite pattern is pretty common in C# code. It’s often used to represent hierarchies of user interface components or the code that works with graphs.

Identification: The composite is easy to recognize by behavioral methods taking an instance of same abstract/interface type into a tree structure.

Example: Structure of the Pattern

This example illustrates the structure of the Composite design pattern. It focuses on answering these questions:

  • What classes does it consists of?
  • What roles do these classes play?
  • In what way the elements of the pattern are related?

Program.cs: Structural Example

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace RefactoringGuru.DesignPatterns.Composite.Structural
{
    abstract class Component
    {
        public Component() { }

        public abstract void Operation();

        public abstract void Add(Component c);

        public abstract void Remove(Component c);

        public abstract bool IsComposite();
    }

    class Composite : Component
    {
        List<Component> children = new List<Component>();

        public Composite() 
		{ 
		
		}

        public override void Add(Component component)
        {
            children.Add(component);
        }

        public override void Remove(Component component)
        {
            children.Remove(component);
        }

        public override bool IsComposite()
        {
            return true;
        }

        public override void Operation()
        {
            int i = 0;

            Console.Write("Branch(");
            foreach (Component component in children)
            {
                component.Operation();
                if(i != children.Count-1)
				{
					Console.Write("+");
				}
                i++;
            }
            Console.Write(")");
        }
    }

    class Leaf : Component
    {
        public Leaf()
        {

        }

        public override void Operation()
        {
            Console.Write("LEAF");
        }

        public override void Add(Component component)
        {
            throw new NotImplementedException();
        }

        public override void Remove(Component component)
        {
            throw new NotImplementedException();
        }

        public override bool IsComposite()
        {
            return false;
        }
    }
	
	class Program
    {
        static void Main(string[] args)
        {
            Client client = new Client();

            Component leaf = new Leaf();
            Console.WriteLine("Client: I get a simple component:");
            client.ClientCode(leaf);
            Console.WriteLine("\n");

            Composite tree = new Composite();
            Composite branch1 = new Composite();
            branch1.Add(new Leaf());
            branch1.Add(new Leaf());
            Composite branch2 = new Composite();
            branch2.Add(new Leaf());
            tree.Add(branch1);
            tree.Add(branch2);
            Console.WriteLine("Client: Now I get a composite tree:");
            client.ClientCode(tree);
            Console.WriteLine("\n");

            Console.Write("Client: I can merge two components without checking their classes:\n");
            client.ClientCode2(tree, leaf);
        }
    }

    class Client
    {
        public void ClientCode(Component leaf)
        {
            Console.Write("RESULT: ");
            leaf.Operation();
        }

        public void ClientCode2(Component component1, Component component2)
        {
            if(component1.IsComposite())
            {
                component1.Add(component2);
            }
            Console.Write("RESULT: ");
            component1.Operation();

            Console.WriteLine();
        }
    }
}

Output.txt: Output

Client: I get a simple component:
RESULT: LEAF

Client: Now I get a composite tree:
RESULT: Branch(Branch(LEAF+LEAF)+Branch(LEAF))

Client: I can merge two components without checking their classes:
RESULT: Branch(Branch(LEAF+LEAF)+Branch(LEAF)+LEAF)