Monday, April 28, 2008

Composite Pattern

Compose objects into tree structures to represent part-whole hierarchies. Composite lets clients treat individual objects and compositions of objects uniformly. Say you have several different types of objects that together form a structure, for example a tree. Take a look at my example below:

Class: Branch
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
namespace Composite
{
    public class Branch
    {
        private readonly List<object> _Children;

        public Branch()
        {
            _Children = new List<object>();
        }

        public void Add(object item)
        {
            _Children.Add(item);
        }

        public void Display()
        {
            Display(1);
        }
        public void Display(int level)
        {
            Console.WriteLine(new string('-', level) + " Branch");
            level++;
            foreach (object child in _Children)
            {
                Branch branch = child as Branch;
                if (branch != null)
                {
                    branch.Display(level);
                    continue;
                }
                Leaf leaf = child as Leaf;
                if (leaf != null)
                {
                    leaf.Display(level);
                    continue;
                }
                Apple apple = child as Apple;
                if (apple != null)
                {
                    apple.Display(level);
                    continue;
                }
            }
        }
    }
}
Class: Leaf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
namespace Composite
{
    public class Leaf
    {
        public void Display()
        {
            Display(1);
        }
        public void Display(int level)
        {
            Console.WriteLine(new string('-', level) + " Leaf");
        }
    }
}
Class: Apple
1
2
3
4
5
6
7
8
9
10
11
12
13
14
namespace Composite
{
    public class Apple
    {
        public void Display()
        {
            Display(1);
        }
        public void Display(int level)
        {
            Console.WriteLine(new string('-', level) + " Apple");
        }
    }
}
As you can see each object has a Display method, but the Display method of the Branch object is also calling its children’s Display method. And to be able to do that it needs to know what type of object it is. That results in the ugly if type name is object as type validation. The Composite Pattern is there to solve that. Take a look below:
Interface: IDisplayItem
1
2
3
4
5
6
7
8
namespace Composite
{
    public interface IDisplayItem
    {
        void Display();
        void Display(int level);
    }
}
Class: DisplayItem : IDisplayItem
1
2
3
4
5
6
7
8
9
10
11
12
13
14
namespace Composite
{
    public class DisplayItem : IDisplayItem
    {
        public virtual void Display()
        {
            Display(1);
        }
        public virtual void Display(int level)
        {
            throw new NotImplementedException();
        }
    }
}
Class: Branch : DisplayItem
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
namespace Composite
{
    public class Branch : DisplayItem
    {
        private readonly List<DisplayItem> _Children;

        public Branch()
        {
            _Children = new List<DisplayItem>();
        }

        public void Add(DisplayItem item)
        {
            _Children.Add(item);
        }

        public override void Display(int level)
        {
            Console.WriteLine(new string('-', level) + " Branch");
            level++;
            foreach (DisplayItem child in _Children)
            {
                child.Display(level);
            }
        }
    }
}
Class: Leaf : DisplayItem
1
2
3
4
5
6
7
8
9
10
namespace Composite
{
    public class Leaf : DisplayItem
    {
        public override void Display(int level)
        {
            Console.WriteLine(new string('-', level) + " Leaf");
        }
    }
}
Class: Apple : DisplayItem
1
2
3
4
5
6
7
8
9
10
namespace Composite
{
    public class Apple : DisplayItem
    {
        public override void Display(int level)
        {
            Console.WriteLine(new string('-', level) + " Apple");
        }
    }
}
See how much nicer this deals with the different child items? Now the Branch does not need to worry about what type of objects its children are, they all inherited from DisplayItem. I hope you found these examples helpful. Also take a look at the following links:

http://www.dofactory.com/Patterns/PatternComposite.aspx
http://sourcemaking.com/design_patterns/composite

No comments: