The way the class Item
is structured, even applying the @ramaral solution, it will be very difficult for the customer to use the item tree.
Customer will always have to check if an item is a node in the tree (if(item.SubItems != null)
) or if the item is a leaf from the tree.
For example, to print the entire tree, the client would have to define a recursive method, and at each iteration determine the type of item.
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);
The ideal would be to restructure the class Item
in order to expose only handling methods, and apply the standard Composite, in order to treat all items, either nodes or leaves, uniformly.
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 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();
}
}
Code of the client
IItem root = //...
foreach(Item item in root)
Console.WriteLine(item.Nome);
The class
Item
will have ways? Or so' dice?– dcastro