December 2, 2009

The Interface Will Set You Free

All too often I see object-oriented programmers jump into coding a project with both feet first, without thinking much about the design of the project. This post is sort of a cautionary tale / exercise to get you thinking about what you should consider before you start to write code. The purpose of this article is to show you how using interfaces can make your code both more reliable and more scalable, as well as easier to maintain.

Imagine that we're creating a new end-to-end POS system for a grocery store called BD Market. Let's assume for the time being that you know (or at least you think you know) everything you need to about the domain. So, like any eager programmer who doesn't want to waste his client's time and money you start creating classes - and here's what you have so far:

Notice any problems? If not, then it's a good thing you're reading this. Take another look at the code above and note the following:
  1. Both PerishableItem and NonPerishableItem have the data members Name, SKU, RetailPrice, and UnitPrice in common.
  2. Each implementation of the Scanner class's Scan and CancelScan methods does the exact same thing.
Let's face it: a real-world grocery store scanner can't tell the difference between a perishable food item and a non-perishable one, so why does your Scanner class need to know the difference? The answer is: it doesn't. Furthermore, what will happen if you create a third item class and forget to add a Scan() and CancelScan() method to your Scanner class for that item type? As you can imagine, the situation gets uglier and uglier the more you think about it.

So, what can we do to avoid this mess now, and make it such that adding additional item types in the future won't break our Scanner class? We're going to create an interface called IProduct, that's what:

The IProduct interface defines signatures for the public properties that we want to expose in the classes that implement this interface. We can then refactor our Scanner class so that only one Scan() and one CancelScan() implementation is needed. See the updated code below:

The biggest (and most helpful) difference you can see is that now we only need one implementation of the Scan() and CancelScan() methods in our Scanner class. This has a future benefit as well, because as long as item types we create in the future implement the IProduct interface we do not have to concern ourselves with updating the Scanner class.

I hope that the brief example above has shown you how using interfaces can help you to write more robust code in your object-oriented projects. Please feel free to send any questions my way at brian (at) brian-driscoll (dot) com, or leave a comment below. You can also follow me on Twitter, I'm @driscollwebdev

No comments: