"Emiel van de Laar" <emiel / il.fontys.nl> schrieb im Newsbeitrag
news:20040727111212.GA17548 / il.fontys.nl...
> Greetings,
>
> Lately I've been pondering about the trade offs one must make when
> implementing classes which maintain internal collections. My question
> is, when is it wise to inherit and when to encapsulate. I've attached
> some sample Ruby code to demonstrate my thinking. My current issues
> are with C# but I believe it to be a general OO issue.
>
> Inheriting from collection classes, i.e. Array, Hash, is simple, fast
> and takes relatively little code. However every method available is
> exposed to the implementing class. Something we don't always want.
>
> Encapsulation(by association) prevents method pollution by exposing
> only what is needed, which gives us more control. For code completion
> this is nice because we aren't confronted with an excessive amount of
> methods; we only see what is needed.
>
> Another benefit of encapsulation is that you can replace your internal
> collection at a later stadium with an alternative implementation,
> perhaps for performance reasons. As long as the interface to the
> implementing class remains the same you are free to do as you
> please internally.

Basically you named all important arguments, so the conclusion is: use
delegation.  Even more so since it is so simple in Ruby (see below).
Inheritance is almost always the wrong choice here.

Bertrand Meyer, the OO guru and inventor of Eiffel, has a different
approach to this: he prefers inheritance and calles it "implementation
inheritance".  But you need a language in which you can do it.  The
difference between Eiffel and other languages is that Eiffel allows to
hide methods that you don't want accessible from the outside for a sub
class instance.  Personally I dislike that because that makes naming a
inheritance relationship "is a" questionable, because the interface of the
sub class is not a superset of the super class's interface and thus both
are not compatible (see also "Liskov substitution principle").

> At times though, it can be a pain exposing all the methods we need;
> sometimes we need them all. I know Ruby offers us the "method_missing"
> feature which I have used a lot, however, as far as I know C# doesn't
> offer me such a luxury.

Think also of Delegator and SimpleDelegator, which make life even easier:

require 'delegate'
class ArrayFoo < DelegateClass(Array)
  def whatever_additional_method_you_need
  end
end

In certain cases (simple scripts) singleton methods may be sufficient, so
you don't need to create a new class at all:

numbers = (1..10).map { rand 10 }
def numbers.max; inject(0){|m,i| i>m ? i : m} end
puts numbers.max


Kind regards

    robert