Sunday 19 July 2009

Aspects of Polymorphism in .NET Part 4 - Interfaces

If you've read parts 1-3 of this blog you'll be aware that we've used the real world objects, cars, to draw a parallel with, and explain, classes, inheritance and abstraction. I hope that, by this stage, you are beginning to undertand and recognise the advantages that come from properly object orienting your code. Flexibility for future development is a key aspect of proper OO design.

Although the code examples in this BLOG have been written in C#, one of the .NET languages, the principles apply to all Object Oriented languages.

So, we now come to Interfaces. What role do they have in object oriented programming?

Contracts

I have often read that Interfaces can be likened to contracts. The thinking behind this analogy is that a class implementing an interface MUST implement ALL of the methods and properties declared by the interface, much the way that an employee MUST carry out all of the responsibilities contained in his contract of employment if he wants to keep his job.

However, I don't really find this analogy to be particularly helpful as it doesn't really explain why you'd bother to create or implement an interface in the first place. So, I'm going to explain the use of interfaces by extending our hypothetical car model already used throughout this BLOG. I sincerely hope that this will clarify the use of interfaces for any of you who are a little confused about them.

Recap

At the end of part three you should have started to see that by abstracting a "Car" class and implementing that abstract class in our "Focus" class we could then build other classes that made use of Cars (generic and flexible) rather than specific models such as Focus (narrow and restrictive). An abstract class was ideal for the "Car" because it allowed us to implement logic that was common to all cars within the abstract class, and declare abstract methods for logic that would have to be implemented by sub classes.

Manual or Automatic?

In the UK (where I'm from) 90% of the cars on the road are manual transmission with the vast minority being automatic. Drivers who take their driving test in an automatic car are restricted to only being able to drive automatic cars. On the other hand, those who pass their test in a manual car can drive either manual or automatic. Modelling this behaviour in our example case is an ideal environment for interfaces.

Although it's not compulsory, it is common practice to precede the name an interfaces with a capital "I". So, let's create interfaces that define manual and automatic cars.

    public interface IManual
{
bool ClutchDepressed
{
get;
set;
}
void ShiftUp(int gearFrom, int gearTo);
void ShiftDown(int gearFrom, int gearTo);
}
public interface IAutomatic
{
void ShiftDrive();
void ShiftReverse();
void ShiftPark();
}
You will notice that our interfaces contain no implementation (i.e. logic that says how to do any of the things declared), they simply declare methods and properties that any implementing classes MUST provide logic for.

So, when the hypothetical engineers at Ford build different models of the Focus, they will implement one of these interfaces depending on the kind of transmission they will be using. Let's go back and update our code in order to implement one of these interfaces.

    public class FocusAuto : Focus, IAutomatic
{
public FocusAuto(Guid keyCode)
: base(keyCode) { }
public FocusAuto(Guid keyCode, int numDoors) : base(keyCode, numDoors) { }

public void ShiftDrive()
{
//... Logic to change the gear into Drive and
// then automatically through the gears as the car moves ...
}
public void ShiftReverse()
{
//... Logic to change the gear into Reverse ...
}
public void ShiftPark()
{
//... Logic to change the gear into Park ...
}

}
You'll notice that I've created a new class, called FocusAuto. This means that we've managed to avoid changing our existing Focus class. Focus, still implements Car, so we still benefit from all of the logic contained in Focus and Car. However, as highlighted in blue, the new FocusAuto class implements the IAutomatic interface. As a result it MUST implement the three methods declared by the interface.

The Benefits

Why put this definition in an interface? After all, the FocusAuto class could easily have contained the logic without implementing the IAutomatic interface. Simply remove the , IAutomatic from the class definition and the code will still compile...

The reason is simple and yet very powerful - and remarkably similar to the benefits we derived from abstracting logic into a Car class...

Earlier I mentioned that interfaces are often likened to contracts. Think about what contracts do... For example, your employment contract defines what is expected of you as an employee. However, it also serves as a marker or identifier for YOU. If you have a contract that defines the role of a C# developer that is what you are.

Interfaces do the same for classes - they act as identifiers for what the class is, or does. So, we can now diffentiate drivers based on what they are allowed to drive. Let's create a new class to demonstrate this

    public class AutomaticDriver
{
private Car myCar;
public IAutomatic MyCar
{
get
{
return (IAutomatic)myCar;
}
set
{
myCar = (Car)value;
}
}
public void Init()
{
Guid _keyCode = new Guid();
if (myCar != null)
{
myCar.Start(_keyCode);
myCar.Accelerate(0, 50);
myCar.Brake();
}
}
}

Because our AutomaticDriver class doesn't really care about who made the Automatic car it drives all it has to do is check that the car is an automatic. Therefore any car that implements the IAutomatic interface will be allowable.
            FocusAuto myAuto = new FocusAuto(new Guid());
AutomaticDriver driver = new AutomaticDriver();
driver.MyCar = myAuto;

Summary

Throughout this BLOG on polymorphism you have seen that there is much to be gained by OO design - designing at the interface level rather than the object level. In fact, this is the basic premise of Design Patterns (recommended for further reading).

I have used a real world parallel in order to convey these concepts because I often find it easier to understand new concepts by looking for every day instances around me. I hope you have found this series to be helpful and insightful.

No comments:

Post a Comment