0

Here’s an example — I want to implement a DropoutStack (a stack with a fixed max size, and will remove the elements from bottom when it is oversized) based on the existing LinkedList in C#. (This is where the idea came from: Limit the size of a generic collection? ) However, there are at least two ways to implement.

1) The New Data Structure (DropOutStack) is inherited from the Existing Data Structure (LinkedList). Just like the answer.

public class LimitedSizeStack<T> : LinkedList<T>
{
private readonly int _maxSize;
public LimitedSizeStack(int maxSize)
{
  _maxSize = maxSize;
}

public void Push(T item)
{
  this.AddFirst(item);

  if(this.Count > _maxSize)
    this.RemoveLast();
}

public T Pop()
{
  var item = this.First.Value;
  this.RemoveFirst();
  return item;
}
}

2) The New Data Structure owns the Existing one. Something like:

public class LimitedSizeStack<T>
    {
    private readonly int _maxSize;
    private LinkedList<T> _list;
    public LimitedSizeStack(int maxSize)
    {
      _maxSize = maxSize;
      _list = new LinkedList<T>();
    }

    public void Push(T item)
    {
      _list.AddFirst(item);

      if(_list.Count > _maxSize)
        _list.RemoveLast();
    }

    public T Pop()
    {
      var item = _list.First.Value;
      _list.RemoveFirst();
      return item;
    }

There are pros & cons for both methods.
For 1: we do not need to care about implementing the common methods such as Clear() and Count; but other methods which is not related to DropOutStack will also be exposed (e.g., Find(), AddBefore()).
For 2: that's the opposite. Unrelated methods are hidden, but we need to reimplement the common methods.

My question is:
1) Is there any convention of implementation, i.e., is it always better to choose one option?
2) Is there any other factors we need to consider (e.g., for efficiency and memory) when making the decision?

Community
  • 1
  • 1
  • I think that in the end it will really come down to preference in terms of difficulty in implementation and exposure of methods. – Jashaszun Jul 07 '16 at 23:53
  • 1
    I think the fundamental design question here is "Is a LimitedSizeStack a Stack" or does it just resemble a stack in some respects?" IsA => inherit else compose. – Skip Saillors Jul 07 '16 at 23:58

1 Answers1

1

You almost never want to use inheritance. Only if you have an abstract base collection that's explicitly meant to be overridden (which LinkedList is not). You're exposing the implementation details of the stack and letting users arbitrarily manipulate it outside your expected public API. A stack shouldn't have stuff like "AddBefore", "AddAfter", "AddFirst", "AddLast".

Also, a linked list isn't a good choice for a size limited stack, an array is much more appropriate for a fixed sized data structure:

public class LimitedSizeStack<T>
{
    private T[] items;
    private int top;
    private int count;
    public LimitedSizeStack(int size)
    {
        items = new T[size];
        top = size - 1;
        count = 0;
    }
    public bool IsEmpty { get { return count == 0; } }
    public T Peek()
    {
        if (IsEmpty)
            throw new Exception("Stack is empty");
        return items[top];
    }
    public T Pop()
    {
        if (IsEmpty)
            throw new Exception("Stack is empty");
        count--;
        var result = items[top];
        top--;
        if (top < 0)
            top += items.Length;
        return result;
    }
    public void Push(T value)
    {
        top++;
        if (top >= items.Length)
            top -= items.Length;
        items[top] = value;
        if (count < items.Length)
            count++;
    }
}
Bryce Wagner
  • 2,640
  • 1
  • 26
  • 43