views:

200

answers:

2

What do I lose by not implementing the Component and treating everything as a Composite?

I have given up the implementation for Leaf node:

I.e.

class Component : IComponent
{ 
    /*...*/ 
}

Now plz take a look at my code.

public interface IComponent
{
    int ID { get;set; }
    string Name { get;set;}
    void Add(IComponent item);
    void Remove(IComponent item);
    List<IComponent> Items { get; }
    void Show();        
}


public class Composite : IComponent
{
    private int _id;
    public int ID
    {
     get { return _id; }
     set { _id = value; }
    }

    private string _name;
    public string Name
    {
     get { return _name; }
     set { _name = value; }
    }

    public Composite(int id, string name)
    {
     _id = id;
     _name = name;
    }

    private List<IComponent> _items = new List<IComponent>();

    public void Add(IComponent item)
    {
     _items.Add(item);
    }

    public void Remove(IComponent item)
    {
     _items.Remove(item);
    }

    public List<IComponent> Items
    {
     get
     {
      return new List<IComponent>(_items);
     }
    }

    public void Show()
    {
     Console.WriteLine("ID=" + _id + "; Name=" + _name);
    }        
}


class Program
{
    static void Main(string[] args)
    {
     IComponent root = new Composite(1, "World");

     IComponent asia = new Composite(2, "Asia");
     IComponent europe = new Composite(3, "Europe");

     root.Add(asia);
     root.Add(europe);

     asia.Add(new Composite(4, "China"));
     asia.Add(new Composite(5, "Japan"));

     europe.Add(new Composite(6, "Germany"));
     europe.Add(new Composite(7, "Russia"));

     root.Show();
     Program.Traverse(root.Items);

     Console.ReadLine();
    }

    static void Traverse(List<IComponent> items)
    {            
     foreach (IComponent c in items)
     {
      c.Show();

      Traverse(c.Items);
     }
    }
}

What is wrong with this approach of Composite Pattern? What kind of problem can I face with this type of design?

+2  A: 

You're giving up any chance to subclass the "Leaf", if it turns out you have different types of "nodes" you'll probably end up polluting the structure in one way or another. And you're violating the single responsipbility priciple too. It is very easy to get pollution of all sorts with the composite pattern, and I think it always pays off to do it cleanly.

krosenvold
What do you mean by 'pollution'? Can you make a little clear?
JMSA
krosenvold
A: 

If I understand correctly, there is not a concept of leaf node, in composite pattern.

Any node which doesn't have a child is automatically a leaf node.
Looking at your code, this is not needed

private List<IComponent> _items = new List<IComponent>();

    public void Add(IComponent item)
    {
        _items.Add(item);
    }

    public void Remove(IComponent item)
    {
        _items.Remove(item);
    }

    public List<IComponent> Items
    {
        get
        {
                return new List<IComponent>(_items);
        }
    }

I am looking at ControlCollection class, which is a property of Control class.

Though not exactly composite pattern, every Control knows of who it is child of, which is missing from your code.

My understanding could be totally off. Experts can correct me :)

EDIT: I looked at the dofactory reference, which seems to have a concept of leaf class in composite pattern. My mistake of totally not understanding it.

But I would suggest you look at the way .net implements kind of composite pattern by having Control, ControlCollection & related classes.

EDIT2: If the code above is to be removed, you will have another class which is a collection of IComponent which you can expose by using a property IList<IComponent>, which in turn will have methods to add/remove.

EDIT3: .net doesn't restrict the user from adding child controls in the above class hierarchy. You could use the dofactory way of design, if you want to restrict the ability for someone to define a leaf node (one that doesn't have any child node).

EDIT4: The way dofactory code shows, you will have to define a leaf node, which will throw NotImplementedException for Add/`Remove'.

shahkalpesh
If I give up this code-section, how would I store children? What should be the mechanism then?
JMSA
OK. Then what would happen to IComponent-interface? The implementation would not be meaningful anymore. This in turn makes the whole design meaningless.
JMSA