Sunday, October 18, 2009

UML Inheritance

With the ambition to make it easy for people to benefit from object oriented approaches using eco and gaffr.net I will in this post give a quick introduction to UML inheritance.

UML inheritance is different from “I get you stuff when you die”. It is also different from “Oh look that kid really looks like her Mother”.

UML inheritance is this: “A child class has all attributes and associations that a parent class has, and the child also has attributes and/or associations of its own that the parent does not have”. In other words UML inheritance is “specialization” and “generalization”; a child class is a “specialized” version of the parent, and a parent is a more “generalized” definition of the child class.

UML inheritance is the same as OO-inheritance (Object oriented inheritance).

UML inheritance will allow you to inherit the properties of multiple parents – but very few OO-languages allow for, so called, multiple inheritance (c++ does, c# & VB.NET does not, and since eco focus on the latter languages eco does not support it either), so I will not mention multiple inheritance again in this post. This means that a class can only have one parent class (or no parent class of course, but never many parents).

An example

Fruit. Fruit is pretty generic class. If we think of specializations of fruit we will find apple, orange, pear, banana, pineapple etc.

image

The lines ending with the big arrow is called a Generalization-association, meaning that if you follow it you get something more generalized of the class that you leave. If you follow it in the other direction you get the opposite of generalization, namely specialization. You will notice in eco and gaffr.net that when you add a generalization associations, the class’s superclass is updated in the object inspector.

image

Superclass is a more correct UML term than “Parent class”. And instead of “Child class” the correct UML terminology is Subclass. So I will use Super- and Subclass from now and on.

Why is inheritance so useful?

The obvious benefit of inheritance is the ability to introduce common properties that all fruit has in one place. If there are properties that all fruit has they will go into the Fruit class rather than defining them over and over in the subclasses.

image

The true power of inheritance is that it resembles how people reason and think. As humans we always generalize. Our language and communication depends on it. This fact is the reason for some bad things in society – prejudice where we jump to conclusions based on earlier experience or hearsay, and some good things – that we instantly know how to use a door knob even if we have never seen that particular type of door knob before.

With the model we have now we can see the benefit that strong types give. Our code will now look like this:

   1: Country malaysia=new Country(this.ServiceProvider());
   2:  
   3: Apple apple = new Apple(this.ServiceProvider());
   4: Orange orange = new Orange(this.ServiceProvider());
   5:  
   6: apple.GrowsInTheseCountries.Add(malaysia);
   7: orange.GrowsInTheseCountries.Add(malaysia);
   8:  
   9: foreach (Fruit fruit in malaysia.ExportsTheseFruits)
  10: {
  11:     if (fruit is Apple)
  12:     { 
  13:       // Do apple specific operations
  14:     }
  15:     else if (fruit is Orange)
  16:     {
  17:         // Do orange specific operations
  18:     }
  19: }

 

Polymorphism

Polymorphism is a fancy word for an important concept: poly==many, morph==shape => many shapes. In our example we use polymorphism in the association from country to fruit; namely a resulting list that can contain different subclasses of fruit – apples and oranges etc.

Polymorphism allows us to operate on stuff we do not really know that much about.  Check this out:

image

I add a method on fruit that I make virtual:

image

I can implement this to return a default value on Fruit and override it on the subclasses that should return a different value:

image

 

   1: public partial class Fruit {
   2:     public virtual bool HasSeedsYouNoticeWhenYouEat()
   3:     {
   4:         return true;
   5:     }
   6: }
   1: public partial class Banana {
   2:     public override bool HasSeedsYouNoticeWhenYouEat()
   3:     {
   4:         return false;
   5:     }
   6: }

So having this I can write code that go over a list of Fruit and ask if the fruit HasSeedsThatYouNoticeWhenYouEat like this:

   1: List<Fruit> crapfruit = new List<Fruit>();
   2: List<Fruit> okfruit = new List<Fruit>();
   3: foreach (Fruit fruit in malaysia.ExportsTheseFruits)
   4: {
   5:     if (fruit.HasSeedsYouNoticeWhenYouEat())
   6:         crapfruit.Add(fruit);
   7:     else
   8:         okfruit.Add(fruit);
   9: }

Did you follow me so far?

If you are still with me I also want to mention the concept of “Abstract”. When we have a model like the one above you should really think of the Fruit class as being abstract – meaning that having an instance of a fruit (a real fruit) that is of type Fruit should not be legal. A fruit-instance must be one of the subclasses; it can be an Apple, Pear, Orange, Banana or PineApple (in our model) but never just “Fruit”.

In Object orientation terms Abstract means that the compiler will treat any attempt to create an instance as an error. It is an error because the developer that defined the class never intended it for direct use, it was designed as an abstraction or generalization of a set of subclasses.

My recommendation is to always treat classes that has subclasses (aka superclasses) as being abstract. In the Fruit sample above this might be obvious, but remember this when you classify your domain where it might not be so obvious.

Are you relatively new to UML or Object Orientation? Download eco for visual studio or the standalone Gaffr.net UML executer to get free access to the tools that will truly help you to evolve your OO-thinking in a direct and fun way.

2 Comments:

Blogger jesper.hogstrom said...

Now, that's a very pedagogic example of inheritance. Well done, Hans.

While your example alludes to it, it may not be as obvious that every instance of a sub-class can be treated as the parent class in every respect, and that every behaviour the parent class has is also present in the sub classes.

A neat example of that is the "ToString()" method in .Net. All you need to do is override it in your subclass to gain the ability to print it. As an example, override it in Person as 'return Firstname + " " + LastName' and in Document as return Filename + "(" + DocType + ")". If you have a list containing Person and Document instances you can print them and get the correct textual representation.

There is an enormous amount of work to save and functionality to gain by carefully considering where in the inheritance chain a feature should be introduced, allowing for future lumping together of sub-classes that in some respect are similar.

Having a persistence framework like ECO that handles inheritance transparently, gracefully and efficiently is worth a lot too!

Often developers with a database background fail to reap the benefits of inheritance, as that concept does not exist on that level. Starting from the model is the way to go in this respect.

--Jesper

October 19, 2009 at 12:21 PM  
Blogger Hans Karlsen said...

Thank you for your comments Jesper! When looking on information as merely data, as database people do, they see it all but still they miss so much when it comes to behaviour, abstraction and understanding. UML is truly a milestone in bridging the gap between thinking and writing (models), and ECO aims to bridge the gap between writing (models) and executing models.

October 22, 2009 at 5:09 AM  

Post a Comment

Subscribe to Post Comments [Atom]

<< Home

 
Contact Us | Terms of Use | Privacy Statement © 2009 CapableObjects