views:

328

answers:

7

Basically I have a custom List class that contains different fruits. Assume that each fruit has an ID number that is stored in the list.

Is it better to have:

new AppleList();
new OrangeList();
new LemonList();

or

new FruitList<Fruit.Apple>();
new FruitList<Fruit.Orange>();
new FruitList<Fruit.Lemon>();

Things to consider:

  • All IDs are of type int.
  • The type of the fruit will not affect the implementation of the List itself. It will only be used by the client of the list, like an external method, etc.

I would like to use the one that is clearer, better in design, faster, more efficient, etc. Additionally if these above 2 techniques are not the best, please suggest your ideas.

EDIT: Btw Fruit is an enum if that wasn't clear.

+4  A: 

It's much easier to maintain 1 generic list than 3 non-generic versions. If you really like the AppleList name you can always use the using trick to name a generic list

using AppleList=Fruit.FruitList<Fruit.Apple>
JaredPar
If he really needs AppleList, then using a "trick" to make it look like AppleList doesn't actually make it an AppleList.
Max Schmeling
I didn't know this syntax used thsi way. SO when I say AppleList, it will create FruitList<Fruit.Apple>?
Joan Venge
@Joan yes that's correct
JaredPar
@Max, I think you're misunderstanding the question. The OP is asking if they should create 3 list types or just one generic one. My solution is allowing for a "friendly" name for a generic list. They should in principle have all the same methods.
JaredPar
+8  A: 

If you use generics, is there a purpose to create the FruitList type? Could you just use List?

There won't be much difference in performance, so I say why create three different classes when one would do the same exactly thing? Use the generic solution.

Max Schmeling
Thanks, yeah FruitList is necessary to implement new interfaces and also have some functionality in there that List doesn't.
Joan Venge
Like what? Couldn't your functionality be served with Extension methods on a normal list? What do you mean by "necessary to implement new interfaces"?
Mystere Man
I wouldn't recommend Extension methods in a class that have control of.
gcores
@gcores: you won't recommend ext methods on a class that we have no control? Just wondering.
Joan Venge
What is that supposed to mean?
Mystere Man
@Mystere Man: Ok so my List is quite different, like I have different interfaces that are relied from other classes which List doesn't implement.
Joan Venge
Exactly, extension methods are *designed* for classes you have no control over, that's their purpose.
Mystere Man
if you control the class, just write real methods. if the methods are shared across classes, write a base class/interface
John Sheehan
Joan, can you give an example?
Mystere Man
I'm just saying that it's better to use inheritance if you can, there's nothing wrong with subclassing List<> and add whatever method you need.
gcores
Be careful though, inheritance and polymorphism is a good thing, but if overdone, it can create a giant tangle of coupling that will make your code harder to modify in the future (which is ironic, because if done well, it has the opposite affect).
Michael Meadows
@Mystere Man: Ok say a property like IsCached in ICacheable. Whoever is using this list has to know if it's cached or not.
Joan Venge
I prefer not to inherit unless I have to, or if it makes more sense to inherit. Extension methods are a perfectly viable way to give things more functionality. After all, that's how LINQ is implemented.
Mystere Man
@Mystere Man: I agree on the ext methods. Another reason why I go with my own types is because, i need total control on the code and I have so many first class types that are used in my app but these types have to conform with so many guidelines that are defined in the app itself.
Joan Venge
The problem with extension methods (currently) is that they may not be supported in all languages. Avoid them if you have to ship your code off to areas you can't control. Also, it may not be obvious to developers what namespace to use in order to get the benefit of your ext methods.
Michael Meadows
That's my only gripe with extension methods... they aren't very "discoverable"
Max Schmeling
@Michael, which language do you use that doesn't support extension methods?
JaredPar
+8  A: 

Use a combo:

public class AppleList : FruitList<Apple> { ... }
public class OrangeList : FruitList<Orange> { ... }
public class LemonList : FruitList<Lemon> { ... }

Put the common logic in the base list class:

public class FruitList<T> : List<T>
    where T : IFruit 
{ ... }
John Sheehan
Thanks, this wouldn't work I think. Because all fruit lists will be 100% the same. But I still need a way to distinguish them externally.
Joan Venge
If they're all the same, then you can just have AppleList : List<Apple>
John Sheehan
Thanks. Is Apple a class in your case? Also why inherit from List? Just wondering.
Joan Venge
Because you get all the functionality of list that you can build on top of
John Sheehan
+3  A: 

Reuse the generic collection classes and subclass them only if you're adding additional functionality. Keep your subclass implementation generic if you can. This is the least complex implementation.

Ken Browning
+1  A: 

Use the Generic list, no point in crating 3 lists and it's always good to keep a level of abstraction. (IFruit would be a good interface).

gcores
IFruit is good for what? It wouldn't apply to the INTEGERS being stored in the list.
Jonathan Allen
A: 

You should assume YAGNI unless you need it. Therefore, if you don't need antyhing more than you get in List, then just List<T>. If for some reason you have to override List, then create

FruitList<T> : List<T> where T : Fruit

If your lists diverge and are no longer polymorphic, then consider implementing your custom lists:

  • AppleList
  • OrangeList
  • LemonList

Try as best you can, however, to keep your inheritance hierarchy as flat as possible to avoid overcomplicating your solution.

Michael Meadows
You were not listening. The list contains integers, not Fruits.
Jonathan Allen
Actually I don't know this: is List not a sealed class?
Joan Venge
List<T> is definitely not sealed.
Michael Meadows
@Grauenwolf Joan stated that the ID is an int. If fruit was an int, then it would be impossible to do this: new FruitList<Fruit.Apple>(); which is included in the example. Apple must be a nested type of Fruit... but thanks for the constructive criticism.
Michael Meadows
No, the List contains Fruit. Maybe only FruitList : List<T> would be enough, and FruitList<T> not necessary, but the answer is still correct.
gcores
Thanks guys. I didn't actually used inheritance on fruits because I used enum. Is this not the better way in this case? I figured if the type of fruit is only important for other methods, why create new classes?
Joan Venge
+2  A: 

•All IDs are of type int.

•The type of the fruit will not affect the implementation of the List itself. It will only be used by the client of the list, like an external method, etc.

Given these two facts, I wouldn't bother with generics. I would put a normal property on FruitList to indicate which type of fruit it is.

Jonathan Allen
Thanks. Can you please tell me what you meant by normal property?
Joan Venge
I think I see what you mean.
Joan Venge