This post is part of a series aimed at bringing people up to speed in what’s going on today in application development.

Time for Inheritance.  Inheritance is pretty much the thing that makes OOP so interesting and can make OO designs wicked complicated, because once you know what inheritance is, you want to do it all the time. (inheritance is like sex?)  From Wikipedia:

a mechanism for creating subclasses, inheritance provides a way to define a (sub)class as a specialization or subtype or extension of a more general class (as Dog is a subclass of Canidae); a subclass acquires all the data and methods of all of its superclasses, but it can add or change data or methods as the programmer chooses. Inheritance is the "is-a" relationship: a Dog is-a Canidae. This is in contrast to composition, the "has-a" relationship, which user-defined datatypes brought to computer science: a Dog has-a mother (another Dog) and has-a father, etc.

 

This time the definition is pretty spot-on (no pun intended).  Inheritance defines “is a” relationships.  With inheritance you start with a base class.  For example, let’s do a simple one and talk about a car (cliché much?).  To keep it simple, let’s say we are designing a mythical system for an automotive manufacturer.  Car might be our base class.  When you think about the base class, you think about the behaviors and data that are shared across all members of that family of objects.  For me, it often helps to think ahead about what types of objects will inherit from the base class and start making a list.  In this case, we are going to have different types of cars, but all cars have a color, an engine, doors, seats, etc.  In addition, to be functional cars, all cars should have the ability to start, to stop, turn, etc.  So looking at it, we have a base class of Car with properties and methods that are going to exist for all cars.

public class Car
{
     private string _color;
     private int _doors;
 
     public string Color
     {
          get{return _color;}
          set{_color = value;}
     }
 
     public int Doors
     {
         get{return _doors;}
         set{_doors = value;}
     }

     public void Start()
     {
           //fire up the engine and go
      }
}

Looking at the very simple class example above, you’ll notice that I have private variables that are being accessed via public means.  This is an example of encapsulation at work from the inside.  Yes, you could just do public string _color; and be done with it, and it would work exactly the same (in this trivial example), but that breaks the principal of hiding internal implementation from the outside world.  I could, for example, remove the “set” block from the Doors property and not allow you to alter that value, making it read-only.  Maybe I work on the assumption that all cars will have 4 doors.  Trivial example.

Anyway, so that’s our base Car.  It exposes two properties and one method that we expect all cars to have.  Now, say we are building out our inventory and manufacturing system, and we make 3 different types of cars:  Sports Cars, Sedans, and Minivans.  Using the language of inheritance, we can say “a Sedan is a Car”, and “a Sports Car is a Car”.  Using inheritance then, we can represent these things in code like this:

public class Sedan : Car
{ }

public class SportsCar : Car
{ }

public class Minivan : Car
{ }

Looking at that, we have 3 classes now that inherit from Car (some languages use a colon to inherit, I think VB has the keyword “inherits”, but regardless of implementation syntax it’s the same concept).  Now, because a Sedan is a Car, we can do this:

Sedan newSedan = new Sedan();
newSedan.Color = “White”;
newSedan.Doors = 4;
newSedan.Start();

Even though there is zero code in the implementation of the Sedan class, we inherited (or sometimes you’ll hear it called derived) the data and behavior from Car, our base class.  Now you might be asking yourself, why bother doing this when we could just make a “type” variable in Car, and call it a “Sedan” or a “Minivan”?  Why go through the trouble of making a base class and then inheriting from it?

The answer is so that you can combine inherited common behavior with new unique behavior so that  you can create new and unique self contained objects.  Remember the idea of cohesion, we want to make our classes do one thing and do them fully.  For instance:  our sports cars are convertibles.  Neither our Sedans nor our Minivans can be convertible.  So to implement a convertible properly, we might have a variable for the color of the top, a variable to hold the state of the top (down or up?), and of course a method to actually put the top down or up.

public class SportsCar : Car
{
      private string _topColor;
      private bool _topDown;

      public bool TopDown
      {
            get{return _topDown;}
      }
      public string TopColor
     { 
           get{return _topColor;}
           set{_topColor = value;}
     }

     public void Convert()
     {
          if(_topDown)
          {
                //put the top up
                _topDown = false;
          }
          else
          {
                //put the top down
                _topDown = true;
          }
     }
}

Now we still have all of the inherited behavior from Car, but we have also implemented our own behavior the exists only for SportsCar.  If we weren’t inheriting and were instead putting the implementation of all the cars into the Car base class, we would have to implement this data and behavior there, but we would also have to check to make sure the car was a sports car before executing the functions for putting the top down or up (you can’t put the top down on a sedan without ruining the car!) and the code gets cluttered and messy.  And then every time you add new behaviors or data for one specific type of car, the Car class gets more and more complicated, harder to maintain, and more prone to bugs.  This would be low cohesion at work, and would lead to horrid code entropy.

One thing to note, back to Encapsulation, you can see a better example of why you encapsulate internal variables within accessor properties.  In this case, I don’t want you to be able to set the state of the top.  I want you to be able to read it, because maybe you will need to if you are implementing a “Draw” function somewhere to draw the car to a screen, but you can’t explicitly set it.  I have provided the accessor but not the mutator of the property.  Instead, it is set internally by the Convert function which puts the top down or up.  Imagine if you could just set the property whenever.  You set _topDown to False when it was True, and then call Convert.  Convert will try to put the top down when it was already down, and cause an error condition.  But since we have encapsulated that behavior and managed it internally, we have eliminated that potential error before it even happened.

Inheritance works on down the line too.  Let’s say that one day you decide that SportsCar isn’t enough, and you want to derive two more specialized sports cars, Ferrari and Corvette, from it.  SportsCar becomes your base class and Ferrari and Corvette inherit all of its behavior, including what it inherits from the Car base class.  Working backward, say your company starts making trucks.  You may decide that you need a new base class, Automobile, and that from there you will have Cars and Trucks.  You can create the Automobile class, make the Car class inherit from it, and it works the same on down the line.  Truck can also inherit from automobile, and Minivan can now inherit from Truck instead of Car, along with Semi and Pickup.  You may hear these situations referred to as an inheritance chain or inheritance tree.


Tags: