Click here to Skip to main content

Example of when Interfaces are incredibly useful

Introduction

Hello my friends.

This article is mainly aimed at beginners/intermediate who are experienced in coding in object oriented style and using polymorphism/inheritance, but never really have understood or implemented interfaces for multiple-inheritance in their programs before.

What I am going to show in this article, is an example of a problem that only interfaces can solve, and that is going to be critical to keep your code clean and readable, and that will also give you a lot more power and flexibility when you are coding object oriented and using polymorphism/inheritance to its full extension.

Before you start, you need to know the basics of interfaces and List<>. A good place to learn interfaces could be here: http://www.codeproject.com/Articles/18743/Interfaces-in-C-For-Beginners

Quick notes about Interfaces: You can think of interfaces like abstract classes that doesn't contain any implementation code, no fields and no static fields. But they can have properties, so they still remain powerful, because they can be used like a normal field. By convention, interface names generally begin with an uppercase I (For example, IMyInterface). Because C# doesn't support multiple-inheritance (for base classes), they provide interfaces instead.

So let's get started 

Say that we are making a game and you have a backpack that can hold a lot of different types of items.

For example:

  • Tools (Potions, Rope, Shovel etc. )
  • Valueable items (Diamond, DragonHorn, DemonEye etc.) 

Tools can be used to do some particular stuff, so it could have an UseItem() function. Valueable items can only be used to sell, so in this case, it doesn't need any functions.

All items should be derived from one base class, because we are going to put all the items in a singleList<> .

So here's the first lines of code.

using System;
using System.Collections.Generic;

namespace ConsoleApplication1
{
    abstract class BaseItem
    {
        public abstract void DisplayName();
    }
    class Diamond : BaseItem
    {
        public override void DisplayName()
        {
            Console.WriteLine("A Diamond");
        }
    }
    class Rope : BaseItem
    {
        public override void DisplayName()
        {
            Console.WriteLine("A Rope");
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            List<BaseItem> myBackpack = new List<BaseItem>();

            myBackpack.Add(new Diamond());
            myBackpack.Add(new Rope());

            myBackpack[0].DisplayName();
            myBackpack[1].DisplayName();

            Console.Read();
        }
    }
} 

OK, so right now, we have put two items in our backpack and those items can display their name. I promised that tools can be used and could have a UseItem() function, and a Rope is a tool so let's add it.

using System;
using System.Collections.Generic;

namespace ConsoleApplication1
{
    abstract class BaseItem
    {
        public abstract void DisplayName();
        public abstract void UseItem();
    }

    class Diamond : BaseItem
    {
        public override void DisplayName()
        {
            Console.WriteLine("A Diamond");
        }
        public override void UseItem()
        {
            //Cant do anything with a Diamond. So we leave this empty.
        }
    }

    class Rope : BaseItem
    {
        public override void DisplayName()
        {
            Console.WriteLine("A Rope");
        }
        public override void UseItem()
        {
            Console.WriteLine("Using my rope");
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            List<BaseItem> myBackpack = new List<BaseItem>();

            myBackpack.Add(new Diamond());
            myBackpack.Add(new Rope());

            myBackpack[0].DisplayName();
            myBackpack[1].DisplayName();

            foreach (var allBackpackItems in myBackpack)
                allBackpackItems.UseItem();

            Console.Read();
        }
    }
}  

Now I added the abstract UseItem() function to the BaseItem class.

For a random reason, we wanted to use all our items at once, so we added the foreach.

I have implemented the UseItem() function inside the base class and not the Rope class, because otherwise we wouldn't be able access the UseItem() function from myBackpack.

That lead us to some some ugliness. Some items like valueable items (Diamond) can't do anything, but are only used to sell, so it do not need any extra functions, but its forced to implement the UseItem() function, so in this case, we leave it empty.

But that is just too damn ugly. We don't want to have classes with empty functions. What we want is one List<> full of different items and one base class for all of our items, that means we don't want to make a List<> of many different base classes like BaseWeapon, BaseValuableItem, BaseTool etc...

So how are we going to solve it with just one List<> and one base class that is able to access the UseItem() function from myBackpack?

Interfaces!  

using System;
using System.Collections.Generic;

namespace ConsoleApplication1
{
    interface IToolItem
    {
        void UseItem();
    }

    abstract class BaseItem
    {
        public abstract void DisplayName();
    }

    class Diamond : BaseItem
    {
        public override void DisplayName()
        {
            Console.WriteLine("A Diamond");
        }
    }

    class Rope : BaseItem, IToolItem
    {
        public override void DisplayName()
        {
            Console.WriteLine("A Rope");
        }
        public void UseItem()
        {
            Console.WriteLine("Using my rope");
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            List<BaseItem> myBackpack = new List<BaseItem>();

            myBackpack.Add(new Diamond());
            myBackpack.Add(new Rope());

            foreach (var allMyBackpackItems in myBackpack)
            {
                IToolItem aTool = allMyBackpackItems as IToolItem;
                if (aTool != null)
                    aTool.UseItem();
            }
            Console.Read();
        }
    }
}  

Here you can see in the foreach, I use the as operator to determine if it is an IToolItem, if it is, then the variable is not null, and then i can use the UseItem() function.

You can also check it with the is operator like this:

foreach (var allBackpackItems in myBackpack)
if (allBackpackItems is IToolItem)
{
    IToolItem aTool = (IToolItem)allBackpackItems;
    aTool.UseItem();
}

or this way;

foreach (var allBackpackItems in myBackpack)
    if (allBackpackItems is IToolItem)
        ((IToolItem)allBackpackItems).UseItem();    

(But using the as operator in this case is faster)

There are a lot more cool things you can do with interfaces, like for example if you have a weapon in your backpack and want to put it in your right hand (if only weapons are allowed to put it on the right hand), then you first have to check if the item you are picking up (e.g. sword) is also an IWeaponItem, by using the is operator.

Or it could also be an armor item where you can only wear it on the torso, so then you have to check if the armor is an ITorsoItem, before you put it in the TorsoSpot.

So Interfaces clearly also gives you a very good overview, just by looking at the class of what it inherits, then you can quickly see what items are of what kind of type and what its used for. Like a DragonHorn item isn't just a IValueableItem, it could also be an item for a quest, so then you could create a IQuestItem and implement it in the DragonHorn class etc. etc...

Another alternative instead of using Interfaces, could be inheriting a baseclass that also inherits another baseclass 

For example:

CursedSword -> BaseWeapon -> BaseItem

This works, but its a little too overkill to make a whole base class that only have a single abstract function e.g. UseWeapon(). You would also lose the overview, because then you have to look in the BaseWeapon class to see what the BaseWeapon class also inherits (if you forgot it).

And even worse, what if the CursedSword was also an item for a quest (because you need to deliver the item to the Skeleton King) and also a tool (because you can open gates with it). Then you would need to inherit base classes four times!

CursedSword -> BaseQuest -> BaseTool -> BaseWeapon -> BaseItem 

Have fun looking around all your base class files just to remember what the CursedSword is inheriting. Also, now all BaseTool items are BaseWeapon items... so now you cant make any tools (e.g. FishingRod) that are not weapons, and now the FishingRod is also forced to implement an empty UseWeapon() function which we wanted to avoid in the first place.

So just forget it and stick to Interfaces (not all the time, but in this case: yes) like this:

class CursedSword : BaseItem, IWeaponItem, IToolItem, IQuestItem
{
    public override void DisplayName() {/* From BaseItem */}
    public void UseWeapon() {/* From IWeaponItem (Can be used to attack untis)*/}
    public void UseTool() {/* From IToolItem (Can be used to open gates)*/}
    public void UseQuest() {/* From IQuestItem (Can be used for the SkeletonKing quest)*/}
} 

Well, that's it for this article (my first article ever written)

I hope you enjoyed it and learned some useful stuff, and hopefully you now got a better grasp of when Interfaces can be really nice to have and use.

Thanks for reading! Smile | <img src=


Web03 | 2.8.160204.4 | Advertise | Privacy
Copyright © CodeProject, 1999-2016
All Rights Reserved. Terms of Service