views:

461

answers:

8

Hi all,

I have faced this problem quite often during the last couple of months, during which I've been building this system. The scenario is this: I have this kind of object that essentially is a list of other objects, but has some other properties specific of its nature. For example:

  • Class Tests:
    • Contains many Test objects
    • Has properties:
      • DefaultTimeouts
      • DefaultNumberOfTries

Should I have this class subclass List<Test> or should I have it inheriting from Object, simply having the list as a property beside the other fields?

I know that this may be a bit subjective and personal taste might play a role here, but I'd wholeheartedly like to know your opinion on this.

+1  A: 

If it literally does everything a List would do, and all the List functions would act on the Tests object in an intuitive way that gives the correct result, then in my opinion it should just subclass List<Test>.

Otherwise, you'll just have a class with a ton of methods which just call a method of the same name on the List<Test> variable in the instance. That'll just be an imperfect extension of the List<Test> class itself.

Claudiu
+1  A: 

Inheritance generally maps to an "is-a" relationship. Since your container is a list, but with some other things, I would inherit from List and add your additional properties to your subclass.

Greg Hewgill
A: 

In your example you said "Class Tests contains many Test objects", not "Class Tests is a collection of Tests objects". IMO it is not necessary to subclass List in this scenario unless you need to have List-like interface for this class.

However, answer really depends on context of Tests class. If it behaves like List and will be used in contexts where List of objects is expected, inherit from List.

Note that inheritance is harder to maintain than composition.

Also, I would rename Tests to TestCollection (if you subclass List), or something like TestUnit (if it would contain list of Test classes.

aku
Good advice on renaming, aku. I'll take that into consideration.I have this awful habit of naming some classes what I should rather name its *instances*, not the classes themselves!
André Neves
+6  A: 

Sub-class from List<T>. If you have the List generic as a property, it isn't as well encapsulated as a sub-class.

If it looks like a List<T> and it sounds like a List<T>, it probably is a List<T>.

I'd call it a TestCollection.

C4H5As
A: 

"Favour composition over inheritance" is always a good rule of thumb. Are the methods that use this class using all of the List methods as well as the ones you add or only the ones you add?

Bedwyr Humphreys
Why would that be a good rule of thumb, Beds? Seems like that concept is key here, right?
André Neves
+1  A: 

I don't think what you have is a simple "list of tests," because you needed something more. I would suggest you call it TestSuite and make the List as a property. Has-a is much easier to maintain compared to inheritance.

In general, I'd be very careful to inherit something like a List.

eed3si9n
Why would you be careful about that?
André Neves
1) Because you don't own and/or understand the source of List, and inheritance introduces tight-coupling between the parent and subclass. 2) Library code can change over time. 3) The consumer of your Class has expectations since List is widely used.
eed3si9n
Thanks for the clarification. However, does 1 imply that one should avoid inheriting from the BCL? Also, I failed to understand 3 as a downside.
André Neves
There are times you might want to inherit from framework, but the basic metaphor/behavior should stay the same. In true "is-a" relationship, subclass should be interchangable at least as metaphor. If I use your class, and it does more than List or different thing from List, I'd feel funny.
eed3si9n
+1  A: 

On reading the answers it seems that the key question is to what length is your object really a list? So maybe a good compromise between the perils of inheritance and the lack of transparency of composition would be to have a List<Test> as a private backend and to expose only the methods which would be used.

André Neves
+10  A: 

Contrary to most of the answers here I wouldn't subclass from List in most cases. I found that inheriting from a class to reuse functionality usually causes problems later.

I usually just have a property of type List (or IList) that returns a reference to the list. Usually you only need a get property here. You can control access to the list by choosing to return a readonly version of the list with .AsReadOnly() or just exposing the list as an IEnumerable.

In cases where I want Tests to be a list I usually implement IList and call an internal List field for the actual implementations of the IList. This is a bit more work and results in some more code to maintain but I've found that this is better maintainable than inheriting List just for it's implementation.

Mendelt
Looks great to me, and kinda matches my own conclusions from the discussion. Thanks!
André Neves
One thing: in cases when you return .AsReadOnly, do you normally return as a ReadOnlyCollection?
André Neves
I would return as an IList, since the fact that it is a ReadOnlyCollection is generally not important to the end-user of the class.
Guvante
Yup. AsReadOnly returns a readonlycollection. If you really need List functionality you shouldn't use it.
Mendelt
Just as a side note to this, FxCop has a rule that states, basically, that you shouldn't ever expose List<T> to the public. Instead, you should either use a read only collection, as recommended in this answer, or a Collection<T>, to be able to change the implementation details without breaking code.
OregonGhost