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

Apr 30 2012

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


Shall we continue?

In part one we set up a simple program and we illustrated some issues with the code. In this part I will introduce you to a slightly better version of the same program. Let us talk about what we are going to do. We have a couple of objectives:

  • Get rid of all the clutter from main
  • Seperate the string processing procedures into their own methods, to make them easier to combine
  • Setup an easier way to display strings in different colours

Lets make some methods

Did you notice a pattern in the first program? We were dealing with a single string, and with each different type of output, all we were doing was outputting a single string. This is a good candidate for a method. We can write a bunch of methods that each take in a string and each return a string. For example:

        static string GetStringInUpperCase(string input)
        {
            return input.ToUpper();
        }

This is the simplest example of extracting it to a method. Sure it might seem a bit daft to extract a single line and put it in a method, but what you are doing is taking that responsibility away from main. Putting it in its own method allows you to update the method with new code, without breaking everything else that uses it, and also without cluttering anything that uses it. The idea here is to move the responsibility away from main, and be able to re-use this bit of code as much as possible.
Lets have a look at another example:

        static string GetStringInReverse(string input)
        {
            var output = "";

            for (var c = input.Length - 1; c >= 0; c--)
            {
                output += input[c];
            }

            return output;
        }

This is a better example, now we have a whole bunch of code which has been removed from the main method and put in its own little box. It has nearly the same signature as before, but it has a different name. The idea with methods is that somebody should be able to tell exactly what a method is for, and how to use it just by looking at the signature and not looking at the actual implementation, and we can see that our signature does this.

static string GetStringInReverse(string input)

If we look at just the signature we are able to work out exactly what the method does AND how to use it. Its self explanatory, and all methods should be like this.

private static string GetStringWithoutVowels(string input)
        {
            var output = "";

            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)
                {
                    output += character;
                }
            }

            return output;
        }

And finally the reverse string method! It does the same thing as before, but again it is factored out into its own method, and the signature of the method tells us exactly what it does and exactly how to use it!

But what about the pretty colors! :(

Don’t worry! This can be factored out too, but we have to do it slightly differently, as changing the colour doesn’t take in a string and it doesn’t need to return anything. What would be great is if we had a way of telling the console to display a string in a certain color, and then to reset the color back afterwards. It will be something that we can re-use over and over again.

        private static void DisplayString(string input, ConsoleColor color)
        {
            var tempColor = Console.ForegroundColor;
            Console.ForegroundColor = color;
            Console.WriteLine(input);
            Console.ForegroundColor = tempColor;
        }

This method, if you look at its signature, takes an input and a colour and displays the input in the specified colour. It makes use of the ConsoleColor enum which is part of the BCL. Once it has displayed the string it then resets the colour to what it was before.
As a way of demonstrating a good candidate for method overloading, we can create new version of this method, which defaults the colour to white:

        //Overloaded version of the display string which uses white as the default color
        private static void DisplayString(string input)
        {
            //Call the full version and give it white
            DisplayString(input,ConsoleColor.White);
        }

All it does is call the other version using the provided input, but with white as the parameter for the colour. Simple enough :D

But wait! What happened to main!?

Don’t worry, I saved the best bit until last. Using the code above we can effectively clean up the main method :)

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

            var upperCase = GetStringInUpperCase(input);
            var reversed = GetStringInReverse(input);
            var withoutVowels = GetStringWithoutVowels(input);

            DisplayString(upperCase);
            DisplayString(reversed);
            DisplayString(withoutVowels);

            DisplayString(upperCase,ConsoleColor.Green);

            Console.ReadKey(true);
        }

See how much cleaner that is now. It is now easier to follow the logic of what main is actually doing. It is more of an overview of logic rather than an explicit list of each and every step. It is also self documenting to a degree, and that is down to how the signatures for each method had been written. If the small parts are named well, then the whole will be much easier to read.
Since we are now dealing with strings and black boxes (the methods), it is now easier to combine functionality. Now if the boss comes in and says “OMG WE NEED IT TO BE IN RED AND UPPERCASE”, we know we can easily do it with the following line:

DisplayString(GetStringInReverse(upperCase),ConsoleColor.Red);

Simples!

Full source code listing


using System;

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

            var upperCase = GetStringInUpperCase(input);
            var reversed = GetStringInReverse(input);
            var withoutVowels = GetStringWithoutVowels(input);

            DisplayString(upperCase);
            DisplayString(reversed);
            DisplayString(withoutVowels);

            DisplayString(upperCase,ConsoleColor.Green);

            DisplayString(GetStringInReverse(upperCase),ConsoleColor.Red);

            Console.ReadKey(true);
        }

        //Overloaded version of the display string which uses white as the default color
        private static void DisplayString(string input)
        {
            //Call the full version and give it white
            DisplayString(input,ConsoleColor.White);
        }

        //Displays a string in a specified color
        private static void DisplayString(string input, ConsoleColor color)
        {
            var tempColor = Console.ForegroundColor;
            Console.ForegroundColor = color;
            Console.WriteLine(input);
            Console.ForegroundColor = tempColor;
        }

        private static string GetStringWithoutVowels(string input)
        {
            var output = "";

            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)
                {
                    output += character;
                }
            }

            return output;
        }

        static string GetStringInUpperCase(string input)
        {
            return input.ToUpper();
        }

        static string GetStringInReverse(string input)
        {
            var output = "";

            for (var c = input.Length - 1; c >= 0; c--)
            {
                output += input1;
            }

            return output;
        }
    }
}

So there are still problems?

You bet! The big problem we have here is how the Program class has so much clutter in it. It has 5 extra methods on it. A good tip to try and remember is to try and keep your classes as clean as possible and to try and give them only one responsibility. This is known as the SINGLE RESPONSIBILITY PRINCIPLE which is often referred to as SRP for short. In general, you will want to try and keep your Program class as simple as possible since its only responsibility is to start the application. Its responsibility isn’t really to display anything or perform any program logic. What would be great is if we were able to separate all of our logic into a set of classes. We will do this in part 3!


Leave a Reply