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

Apr 30 2012

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


So what’s next?

So, in part two we refactored our program and de-cluttered our main method, and made our code a bit better and easier to read, but there were still a few problems. Our program class was still full of stuff which should be put elsewhere. Lets have a look at our objectives for the next version:

  • De-clutter the whole program class. Lets get it as clean as we can
  • Make classes for each of the string processing methods that we have now
  • Make a class to handle the displaying of coloured strings to the screen

Let us begin..:D

This time around I have put each class into a file of its own. One class per file is how myself and most people usually work in C#. I have kept them all in the same namespace for simplicities sake. Moving the functionality from the methods to classes was a very simple job. The body of the methods didn’t need to change at all. Have a look at the following classes:

//StringToUpperMaker.cs

namespace Way_03
{
    public class StringToUpperMaker
    {
        public string GetStringToUpper(string input)
        {
            return input.ToUpper();
        }
    }
}

//StringReverser.cs

namespace Way_03
{
    public class StringReverser
    {

        public string ReverseString(string input)
        {
            var output = "";

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

            return output;
        }

    }
}
//StringVowelRemover.cs

namespace Way_03
{
    public class StringVowelRemover
    {
        public string RemoveVowels(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 there we have it. Three instance classes which separate the functionality out and away from the Program class. It may seem a bit extreme to put them in their own class with only a single method, but it isn’t really, and it doesn’t take much extra work to do it, but the extra functionality afforded to you by doing it is immense. Now you are able to give your string processors their own sets of data to work with, and they are fully independant now. They are only dependant on themselves, but we haven’t lost any functionality. This can only be a good thing.

What about displaying the strings

I have thought about this, and I have extracted the two display methods from the program class and put them into their own class. Take a look:

//StringDisplayer.cs

using System;

namespace Way_03
{
    public class StringDisplayer
    {

        public void DisplayString(string input)
        {
            DisplayString(input, ConsoleColor.White);
        }

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

Now you may notice that this class contains BOTH of the display methods and you may be wondering why I didn’t make two classes for this? Well, if you think about the single responsibility principle, I think this class is okay, because the class as a whole still only has one responsibility if you think about it. Its responsibility is to display strings to the user and it uses two methods to fulfill this responsibility.

I bet the program class is much cleaner now

Yup! And its all because we have taken all extraneous information out of it and put it somewhere else. Have a look:


// Program.cs

using System;

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

            var displayer = new StringDisplayer();
            var upperMaker = new StringToUpperMaker();
            var reverser = new StringReverser();
            var vowelRemover = new StringVowelRemover();

            displayer.DisplayString(upperMaker.GetStringToUpper(input));

            displayer.DisplayString(reverser.ReverseString(input));

            displayer.DisplayString(vowelRemover.RemoveVowels(input));

            displayer.DisplayString(upperMaker.GetStringToUpper(input),ConsoleColor.Green);

            Console.ReadKey(true);
        }
    }
}

Much cleaner now, and because of that, it is actually easier to tell at a glance what it does.

We are making good progress, but there are still some problems

First of all, let us not forget the program that we started with back in part one, it consisted of just a main method with all of this stuff written inside of it. Sure it did the same thing, but if you needed to continue working on the code, would you prefer to improve this new version, or the original version? Which do you think would be easier to work with? I hope you picked this one.
One of the problems with this version is that the StringDisplayer class has to rely on the Program class to feed it strings to display, but it shouldn’t have to really since the other classes all provide strings. It is like we have a middle-man that can be got rid of. Of course we could have each of the string generating classes inside of StringDisplayer, but that isn’t really a good idea either. For one thing it violates the single responsibility principle, because StringDisplayer should be concerned only with displaying strings and nothing more. Also it would be difficult to maintain as you added more string generating classes. Every time you added a new string generating class you would have to update the StringDisplayer class, and this is bad and it makes your code harder to manage.

In the next part I will demonstrate how to use interfaces to take this to the next level.


Leave a Reply