Dot Net For All

Composite pattern with two Examples

In this article I will discuss the Composite pattern with two C# code examples. One is the usual leaf node example and other being the binary tree structure example.

You can find about other design pattern in the series at the below link:

Design Patterns in C#

What is Composite Pattern ?

Composite pattern is another structural pattern which is used to handle the collection of objects which can be of same type. It makes the iteration and traversal of the object in the collection simple and convenient.

Client treats the parent and child or Node and leaf in same manner. This is a very simple and important pattern which we should be aware of. It has high usability and low complexity level.

Design Components in the Composite Pattern

Composite pattern is made of Component and Composite classes. The composite pattern has a collection of the component. The common functionalities of both of these classes are abstracted out in an interface.

In my implementation of the composite pattern I will consider the Leaf and Node class as same. If a node class does not have children I will consider it as the Leaf Node.

The first example I will discuss here is of simple parent- child scenario. In this scenario a single parent class can have many children class. Please have a look at the code below

 public interface IComposite
    {
        int Value { get; set; }
        void Print();
    }

    public class Composite : IComposite
    {
        private int value1;

        public int Value
        {
            get { return value1; }
            set { value1 = value; }
        }

        public IList<IComposite> Nodes { get; set; }

        public void Print()
        {          
            if (Nodes != null)
            {
                Console.WriteLine("I am parent. My Value: " + Value);
                foreach (var item in Nodes.OrderBy(item => item.Value))
                {
                    item.Print();
                }
            } 
            else
            {
                 Console.WriteLine("I am Leaf.My Value: " + Value);
            }           
             
        }
    }

In the above code I have single class which acts as component and composite. If the composite does not have any Nodes then it will be a Leaf.

Lets call this code from the client.

  var level41 = new Composite() { Value = 8 };
            var level42 = new Composite() { Value = 9 };

            var level31 = new Composite() { Value = 4, Nodes = new List<IComposite>() { level41, level42 } };
            var level32 = new Composite() { Value = 5 };
            var level33 = new Composite() { Value = 6 };
            var level34 = new Composite() { Value = 7 };

            var level21 = new Composite() { Value = 2, Nodes = new List<IComposite> { level31, level32 } };
            var level22 = new Composite() { Value = 3, Nodes = new List<IComposite> { level33, level34 } };

            var level11 = new Composite()
            {
                Value = 1,
                Nodes = new List<IComposite> { level21, level22 }
            };

            level11.Print();

and the output of the above code is as following.

Composite pattern

As we can see from the above code there is only single operation which is common for child as well as parent class. The method is Print(). Client only calls Parent method of the top most parent we get the desired result.

Binary Tree Example

As promised I will discuss this article with two examples of composite pattern. Other very good example of composite pattern is binary tree. A binary tree always have two children. In the binary tree which I have created, the parent is greater then the left child and less then the right child.

Lets create  the binary tree using composite pattern.

public interface ICompositeTree
    {
        int Value { get; set; }
        int Level { get; set; }
        IList<ICompositeTree> Leafs { get; set; }
        ICompositeTree LeftNode { get; set; }
        ICompositeTree RightNode { get; set; }
        void Add(ICompositeTree node);
        ICompositeTree Search(ICompositeTree node);
        void Traverse();
    }

    public class Node : ICompositeTree
    {

        private int value1;
        private ICompositeTree leftNode;
        private ICompositeTree rightNode;
        private int level;
        private IList<ICompositeTree> leafs = new List<ICompositeTree>();

        public int Value
        {
            get { return value1; }
            set { value1 = value; }
        }

        public ICompositeTree LeftNode
        {
            get { return leftNode; }
            set { leftNode = value; }
        }

        public ICompositeTree RightNode
        {
            get { return rightNode; }

            set { rightNode = value; }
        }

        public int Level
        {
            get
            {
                return level;
            }
            set { level = value; }
        }

        public IList<ICompositeTree> Leafs
        {
            get
            {
                return leafs;
            }

            set
            {
                leafs = value;
            }
        }

        public void Add(ICompositeTree node)
        {
            if (node.Value > Value)
            {
                if (RightNode == null)
                {
                    RightNode = node;
                    RightNode.Level = Level + 1;
                }
                else
                {
                    RightNode.Add(node);

                }
            }
            else if (node.Value < Value)
            {
                if (LeftNode == null)
                {
                    LeftNode = node;
                    LeftNode.Level = Level + 1;
                }
                else
                {
                    LeftNode.Add(node);

                }
            }
            leafs.Add(node);
        }

        public ICompositeTree Search(ICompositeTree node)
        {
            if (node.Value == Value)
                return this;
            else
            {
                if (node.Value > this.Value)
                    return RightNode.Search(node);
                else if (node.Value < this.Value)
                    return LeftNode.Search(node);
                else
                    return null;
            }
        }

        public void Traverse()
        {            
            if (LeftNode == null && RightNode == null)
                Console.WriteLine(string.Format("Value: {0} Level: {1}", Value, Level));
            else if (LeftNode != null)
                LeftNode.Traverse();
            else if (RightNode != null)
                RightNode.Traverse();

            Console.WriteLine(string.Format("Value: {0} Level: {1}", Value, Level));
        }
    }

The above code is used to create a binary tree structure. These structures can be used for fast searching and iteration of child objects.

We can use composite pattern when:

Conclusion:

In this article I have discussed composite pattern with C# example and given two very good examples of the scenarios where we can use this pattern.

 

Top career enhancing courses you can't miss

My Learning Resource

Excel your system design interview