Parent class with the same responsibility as the child class

3

I have my Item class

public class Item
{
   public string Nome {get;set;}
   public decimal Valor {get;set;}

   public ICollection<SubItem> SubItens {get;set;}
}

public class SubItem 
{
   public string Nome {get;set;}
   public decimal Valor {get;set;}
}

I have these two classes

What happens is that when I have SubItens , the value of class Item should be undone, but when I do not have subitens the value of class Item is the valid value. >

Well, it's kind of confusing, but in my business rule an implementation based on it is needed.

My question is, is it okay to have this? What would be the best way for me to make it easier? Using Inheritance?

    
asked by anonymous 27.11.2014 / 22:43

4 answers

0

You can simplify for one class only:

public class Item
{
    [Key]
    public int ItemId { get; set; }
    public int? ItemPaiId { get; set; }

    public string Nome {get;set;}
    public decimal Valor {get;set;}

    public virtual Item ItemPai { get; set; }
    public virtual ICollection<Item> SubItens {get;set;}
}

I think it solves the whole problem.

    
27.11.2014 / 22:49
8

I do not know what the purpose of class is, but starting from your code, I think this is enough:

public class Item
{
   public string Nome {get;set;}
   public decimal Valor {get;set;}

   public ICollection<Item> SubItens {get;set;}
}

There is no need for a SubItem class because a SubItem is no more than a item .
Conclusion you've already taken when you've acknowledged that Item and SubItem have the same responsibility     

27.11.2014 / 23:31
0

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);
    
28.11.2014 / 15:22
0

You can put a small logic in get of Valor of Item .

In the example below, if the object Item has some SubItem , the Valor property of Item will return the sum of Valor properties of its SubItem

public class Item
{
    private decimal valor;
    public string Nome {get;set;}
    public decimal Valor 
    {
        get
        {
            if (this.SubItens != null && SubItens.Any())
                return this.SubItens.Select(subItem => subItem.Valor).Sum();
            return this.valor;
        }
        set
        {
            this.valor = value;
        }
    }

    public ICollection<SubItem> SubItens {get;set;}
}

public class SubItem 
{
    public string Nome {get;set;}
    public decimal Valor {get;set;}
}
    
21.02.2015 / 22:47