“One program, Four ways” – A beginner’s guide to abstraction and interfaces in C# (Part one)

Apr 29 2012

“One program, Four ways” – A beginner’s guide to abstraction and interfaces in C# (Part one)


Introduction

A few of the people I know who are currently learning C# and object oriented programming and design have been sharing with me their problems in getting their heads around object oriented design. I have decided to try and help by working up an example which shows a program written 4 ways; Starting out with bad design and illustrating the problems with the design, each iteration will be a more advanced version until I feel I am happy with the overall design.

So lets begin!

For myself, the process of learning how to write better code was an iterative one. When you are just starting out it is easy to code yourself into a corner with object oriented programming. You find yourself against a wall of problems. Over time you work out how to solve the problems and eventually you start avoiding the problems before they become a problem altogether.

The example I am going to show has some problems. In this part of the tutorial I will show you the code for a simple program and illustrate some problems that it has. By problem, I mean some kind of problem in the design, and this is important to realise. Each of the four editions of the program will produce the same output, but they will work differently under the hood. The difference will be how easy it is to alter / expand / remove functionality in them, so when I say code has a problem, it means that it is difficult to change or expand the program, and changing the code it to a better design will make it easier to modify and expand it. This is the whole point of object oriented design. The process of changing the code in such a way to improve the design without changing the output is called refactoring.

The program!

I decided to keep the program in question very simple. All it does is take some input from the user, and then displays the input back to the user in a number of different ways. Check out the source code below:-

using System;

namespace Way_01
{
    class Program
    {
        static void Main()
        {
            Console.Write("Please type some text: ");
            var input = Console.ReadLine();

            //Display the input, but in capital letters
            Console.WriteLine(input.ToUpper());

            //Display the input, but in reverse
            for(var i = input.Length-1; i >= 0; i --)
            {
                Console.Write(input[i]);
            }
            Console.WriteLine();

            //Display the input, but without any vowels
            var vowels = new char[] {'A', 'E', 'I', 'O', 'U', 'a', 'e', 'i', 'o', 'u'};
            foreach(var character in input)
            {
                var vowelFound = false;
                foreach (var vowel in vowels)
                {
                    if(character == vowel)
                    {
                        vowelFound = true;
                        break;
                    }
                }
                if (!vowelFound)
                {
                    Console.Write(character);
                }
            }

            Console.WriteLine();

            Console.ReadKey(true);

        }
    }
}

When you run it, you get the following output:

Please type some text: The quick brown fox jumps over the lazy dog
THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG
god yzal eht revo spmuj xof nworb kciuq ehT
Th qck brwn fx jmps vr th lzy dg

As you can see it is very simple, but it does have a couple of issues.

Problem one: Adding functionality is tricky

If we wanted to add more functionality to this program in order to show the input in another way (For example in a different colour or by swapping words around) then our only way would be to add additional code, like this:

            //Adding functionality - Display the input in green

            Console.ForegroundColor = ConsoleColor.Green;
            Console.WriteLine(input);
            Console.ForegroundColor = ConsoleColor.White;

Of course, it isn’t too difficult to do it in this example, but this is just filling up our main method with lots of stuff that isn’t really relevant. Imagine that these bits of functionality are only small parts of a much larger program (A large program with lots of more important parts) and it becomes clear that adding functionality in this way is going to make things less manageable down the line.

Problem two: Combining functionality

Suppose that we wanted to have an extra line of output, but this time it displays the input text in reverse AND in capitals AND in green. Of course we can do this easily by adding extra lines to our program as follows:


            //Display the input, but in reverse AND in green AND in capitals
            Console.ForegroundColor = ConsoleColor.Green;
            for (var i = input.Length - 1; i >= 0; i--)
            {
                Console.Write(input[i].ToString().ToUpper());
            }
            Console.ForegroundColor = ConsoleColor.White;
            Console.WriteLine();

Ok so that works fine right? NO!

Whilst the program displays the expected message, this way of coding is not a good idea. There is an important rule of programming that it is a good idea to live by, and it is DON’T REPEAT YOURSELF often abbreviated to DRY. Here we have repeated ourselves by writing three bits of functionality twice, and this is never a good idea, because we want both versions of the functionality to behave the same way, which means if we change one version we have to go back and change the other version too, and this is more difficult to manage.

But the program works…

Yep, but now suppose your boss comes in and says “Ok, so we need it to show in green, in lowercase, but not in reverse” or “we need it in reverse and uppercase, but not in green”. For each of these problems you have to write a big chunk of code and it can very easily become unmanageable.

So what`s the solution then?

The solution is to refactor the code and improve its design. We will look at that in part two.


Leave a Reply