Object model design & inheritance

Object model design & inheritance

Old forum URL: forums.lhotka.net/forums/t/1703.aspx


SonOfPirate posted on Tuesday, November 07, 2006

I have a question regarding the approach used when constructing a set of base classes with slightly different behavior.  In my experience, the reason you would use inheritance is to achieve code reuse and leverage the behavior that exists in the base class while adding some new functionality (of value) in the derived class.  However, there has been a lot of talk in this forum about shying away from inheritance unless it is clear that this is true - I get that.

Where my confusion comes from is the contradiction that I see in the core .NET framework and the approach Rocky has taken with regards to collection classes.

As I see it, you have four basic types of collections:

  1. Collection - unordered group of objects, no indexing, accessed using an enumerator
  2. List - indexed group of object accessed by position (index) or enumerator
  3. Keyed(Collection or List) - group of objects that may be accessed using a key value that is found in one of the object's properties
  4. Dictionary - group of objects that may be accessed using a key value that is not part of the object itself and is stored in a key/value pair

Given this explanation, a List is simply a Collection that adds indexing and a KeyedCollection is a Collection that adds support for keys.  (Likewise, a KeyedList would be a List with support for keys).  A Dictionary is out there on its own except that it is a Collection whose items are Key/Value pairs instead of the actual object itself.

For the Dictionary, it is clear that inheritance is not appropriate as most of the Collection class' methods would have to be overridden to support the key/value nature of the Dictionary.  So, very little code reuse and/or behavior is being preserved.  However, in the case of the Collection->List->KeyedList (let's say), I can see how all of the behavior in the Collection class is reused by the List class with the value added indexing capability.  And likewise with the KeyedList to the List class where you would need to override the Add() method but still delegate to the base class functionality to actually add the item once the key was pulled out and stored.

In CSLA, inheritance is used by having the ReadOnlyListBase inherit ReadOnlyBindingList. I am curious why BusinessListBase does not inherit ReadOnlyListBase and add write capability?  Isn't this a candidate for inheritance based on the same concepts?  It would leverage the behavior that already exists in ReadOnlyListBase but add new behavior such as Add(), Insert(), Clear(), Remove(), etc.  Can anyone explain the rationale behind not inheriting?

To further confuse me, Microsoft almost never uses inheritance for the collection classes in the FCL.  With the exception of System.Collections.ObjectModel.KeyedCollection<K,T>, System.Collections.Specialized.NameValueCollection and System.ComponentModel.BindingList<T>, none of the myriad of collection classes use inheritance.  I'm thinking there is a ton of code duplicated amongst these objects and am struggling to understand why inheritance wouldn't be used here.

So, as I am working on my own classes, I am struggling with when it is and when it isn't appropriate to use inheritance in cases when it seems intuitive to me to do so.  Any thoughts?

Thanks in advance.

 

Bayu replied on Tuesday, November 07, 2006

Hey there,

Let's see if I can make some sense of this ....

SonOfPirate:

In CSLA, inheritance is used by having the ReadOnlyListBase inherit ReadOnlyBindingList. I am curious why BusinessListBase does not inherit ReadOnlyListBase and add write capability?  Isn't this a candidate for inheritance based on the same concepts?  It would leverage the behavior that already exists in ReadOnlyListBase but add new behavior such as Add(), Insert(), Clear(), Remove(), etc.  Can anyone explain the rationale behind not inheriting?

The main focus of ReadOnlyLists is to be lean and mean. This not only involves the list, but also the objects contained in the list (ReadOnlyBase sub-classes). The main driving force behing BusinessListBase and BusinessBase is all the fancy CSLA stuff: authorization, validation, CRUD, etc. etc. Two (highly) different scenario's, so there is your argument in favor of two distinct objects.

Probably you could make BusinessListBase derive from ReadOnlyListBase. And then (because of the use of generics) you should also have to make BusinessBase derive from BusinessBase. Then all the cool stuff would be added at the BusinessBase level. But this yields one potential problem: you would be able to put BusinessBase classes in your ReadOnlyListBase list. Ouch...... The opposite solution (make ReadOnlyListBase and ReadOnlyBase derive from BusinessListBase and BusinessBase) is even less desirable: your readonly objects become way too bulky (by inheriting all the business-fanciness).


SonOfPirate:

To further confuse me, Microsoft almost never uses inheritance for the collection classes in the FCL.  With the exception of System.Collections.ObjectModel.KeyedCollection<K,T>, System.Collections.Specialized.NameValueCollection and System.ComponentModel.BindingList<T>, none of the myriad of collection classes use inheritance.  I'm thinking there is a ton of code duplicated amongst these objects and am struggling to understand why inheritance wouldn't be used here.



The core Collection classes in the framework are heavily optimized for performance. It is not just an augmented array or so, there is a lot of background adminstration going on in order to ensure maximum performance for each of these classes (Collections/Lists/Dictionaries). So the strategies employed internally in each of these classes to maintain the set of items are very specific and don't lend themselves for reuse. In addition: list behavior is rather straightforward (Add/Remove/Item(index) ...), so the code that could still be reused (despite the specific optimizations) is not really a big gain.

So apparently Microsoft chose to comply with some interfaces (like IList) instead of deriving from the same base class. Also: since the introduction of Generics it would become a bit combersome to program against base-classes. You would have to go the 'generics'-way throughout your own code if you wanted to be agnostic to a particular list type.

Hope this clarifies a bit.

Regards,
Bayu

Copyright (c) Marimer LLC