Since the Item
class is structured, even applying the @ramaral solution, it will be very difficult for the client to use the item tree.
The client will always have to check if an item is a tree node ( if(item.SubItems != null)
) or if the item is a leaf of the tree.
For example, to print the entire tree, the client would have to define a recursive method, and at each iteration determine the item type.
public void PrintNode(Item item)
{
if(item.SubItems == null) //é folha?
Console.WriteLine(item.Name);
else //é nó?
foreach(var subItem in item.SubItems)
PrintNode(subItem);
}
Item root = //criar a arvore
PrintNode(root);
Ideally, you should restructure the Item
class to expose only manipulation methods, and apply the Composite < a> in order to treat all items, be it knots or sheets, evenly.
public interface IItem
{
void Do(Action<Item> action);
}
public class ItemComposite : IItem
{
private readonly IEnumerable<IItem> _subItems;
public ItemComposite(IEnumerable<IItem> subItems)
{
_subItems = subItems;
}
public void Do(Action<Item> action)
{
foreach(var subItem in _subItems)
subItem.Do(action);
}
}
public class Item : IItem
{
public string Nome {get; private set;}
public decimal Valor {get; private set;}
public Item(string nome, decimal valor)
{
Nome = nome;
Valor = valor;
}
public void Do(Action<Item> action)
{
action(this);
}
}
Client code to print the tree:
IItem root = //construir árvore
root.Do(item => Console.WriteLine(item.Nome));
Another possible implementation with support for IEnumerable<T>
public interface IItem : IEnumerable<Item>
{
}
public class ItemComposite : IItem
{
private readonly IEnumerable<IItem> _subItems;
public ItemComposite(IEnumerable<IItem> subItems)
{
_subItems = subItems;
}
public IEnumerator<Item> GetEnumerator()
{
return _subItems.SelectMany(subItem => subItem).GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
public class Item : IItem
{
public string Nome { get; private set; }
public decimal Valor { get; private set; }
public Item(string nome, decimal valor)
{
Nome = nome;
Valor = valor;
}
public IEnumerator<Item> GetEnumerator()
{
yield return this;
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
Customer Code
IItem root = //...
foreach(Item item in root)
Console.WriteLine(item.Nome);