Like many VB programmers, I'm only marginally familiar with implementation inheritance. Oh, sure, I understand it in theory -- I've read all the standard primers ("A dog and a cat are both animals, but they speak differently...") -- but I have yet to use it in a real application. So I was enthusiastic when it looked like my current application, a content management system written in ASP.NET, would provide an ideal opportunity to get my feet wet with implementation inheritance.
The app deals with content objects which are displayed within placeholders in page templates. When a page is requested, the system retrieves the relevant content from the database, binds the data to a user control, then inserts the user control into a placeholder on the page. There are several types of content: home page lead, home page non-lead, feature article, product review, etc. As I designed the various content objects, it occurred to me that they shared certain features in common: they all, for example, had a title, description and publication date; all home page items had a URL to which they linked; all article types had an author and one or more pages. They all needed to know how to load themselves from and save themselves to the database. So, I thought, why not create a base ContentItem class containing the shared properties and methods, and inherit the more specific types from this base class?
In my initial proof-of-concept, that's exactly what I did. Specific content types inherited from a base ContentItem class; when they were serialized to the database, they looked like this. Everything worked as expected; this inheritance stuff was a piece of cake!
As I started to flesh out the prototype, however, it became apparent that my design was pretty maintenance-intensive. Each new content type required me to create two user controls and associated code-behind classes: one of each to load/edit/save the content, and another to display it on a page. Although the new classes could inherit common functionality from my ContentItem and ContentDisplay base classes, I'd still have to create, test and debug them. In addition, the XML stored in the database was version-specific: If I later changed the design of a class, it wouldn't know how to deserialize data saved by an earlier version of the class.
One way to reduce the maintenance burden, I thought, would be to create a generic edit form: The form's code could read its layout from an XML file and dynamically create the necessary controls. That was simple enough (I'll write about it in a future article); the hard part was figuring out what to do when the user clicked the 'Save' button: I'd still have to create an instance of the correct content class and manually assign the form's field values to the associated class properties. Nor did this approach do anything to reduce my class development burden, or avoid the version-specific nature of the serialized XML.
Finally, I concluded that inheritance was not a good fit for this application; it was simply more trouble than it was worth. I refactored the design to use a generic content object, which consists of a simple collection of items. My generic edit form could save itself by simply looping through its controls and adding a name-value pair to the content object's Items collection. I'd no longer have to create new classes for each new content type, and the serialized XML would no longer be version-specific: the content object would neither know nor care what items it contained. To add a new content type, all I'd have to do is create a simple form definition file, and a user control to display the content.
Is it just me, or is this a well-known downside of implementation inheritance? Does inheritance work best in cases where the object model is relatively static? Or are there ways to efficiently handle situations like this one, and I just don't know them yet?
Comments
Posted by Richard Caetano on November 28, 2002:
Posted by Mark Hurd on December 10, 2002:
I think you’ve highlighted the power of structured storage like XML. However, I also agree that good real-world uses of implementation inheritance are hard to find. One wonders how many evolutions the .NET Windows.Forms hierarchy went through before it came to be the current rather elegant design.
Posted by Alan Kleymeyer on July 15, 2003:
I agree, it depends on the situation. You may have some requirements that make inheritance, not the optimal solution but it is not a reflection of inheritance, just the particular problem you are trying to solve.
Posted by Mike Gale on August 26, 2003:
There are so many ways of designing an application. Benefits and problems are not always known when you get started.
I think the key issue is evolving the design. It’s often called refactoring these days but it has been going on for a very long time.
With content management (CMS) I’ve tried blends of relational data and XML data. I’m inclined to say put a lot in the XML but some people (like MS when they ASPX’ed MSDN) have found that creating the XSLT’s to transform the data is more work than anticipated.
Posted by Al Meadows on March 23, 2004:
A lot of what inheritance buys you (extending a base class on and on and on again) could be solved simply by have the ability to create a text file of code sections and use an Include…end Include structure to have the compiler/IDE include it where indicated.
Posted by Dave Bacher on January 13, 2005:
Al,
#include certainly works for small projects, that are small in scope and don’t have a lot of problems.
when class A inherits from class B, no code is duplicated. This is important in a large project, and it is important in an Enterprise application. It is even more important when class B is contained in a different assembly from class A, because that means updates to that assembly (bug fixes, security fixes, etc.) propogate without having to update both assemblies.
For example, lets say you have 6 applications that run against the same database. These applications talk over a peer to peer network, using the same protocol. They write messages to and from the peer network, and XML makes the messages big, bloated and slow to process, so you’ve used a binary format instead to be able to handle more messages in a given time frame.
If you make a change and have to rebuild the applications, you have to determine which users have which application installed, which applications use the code, etc.
If you make a change to the library, you can just distribute that to your users, and regardless of which applications they are running, the upgraded library will kick in and give them what they’re after.
If that makes sense.
Posted by Shaun M on June 21, 2005:
I actually used inheritance fairly solidly in a program I wrote for a local liquor store. There was a base ‘person’ class which was inherited to create supplier, customer, employee and shipper classes. It worked out nicely because the owner wanted to be able to see all of the people he deals with and filter them on the fly either by entering keywords or checking employee/customer/supplier/shipper checkboxes. To do this we had one big table (which made our dba rip his hair out during design :P) for all of the personnel and just dumped the contents of each object into it.
However, inheritance didn’t work when we tried to set up a base ‘beverage’ class then inherited to make ‘beer’, ‘wine’, ‘spirits’ and ‘non-alcoholic’ classes.. It was just too much work for the little bit of good gained.
One place inheritance would be nice would be in XHTML, granted there are ways to simulate it, I would still like to write an xhtml file that has a header, footer, content section and all the styling, then inherit that into new pages that require, say, a sidebar or just to save rewriting code. And yes, there are ways with ASP or SSI but there are projects too small to warrant setting up a Windows server or configuring an Apache server to run it.
Posted by Sudhindra on January 16, 2006:
Well, here is (http://www.javaworld.com/javaworld/jw-08-2003/jw-0801-toolbox.html) a java-related article that has a nice discussion on implementation inheritence.
Leave a comment
I think it depends on the situation. Inheritance isn’t a tool for every problem…but some problems are nicely solved by it.
I’ll see if I can dig up some code that I’ve found to be nice cases for inheritance in the real world.