#446 – Deciding Between an Abstract Class and an Interface

An abstract class is a base class that may have some members not implemented in the base class, but only in the derived classes.  An interface is just a contract that a class can choose to fulfill–a list of member that it must implement if it implements the interface.  (Differences Between an Interface and an Abstract Class).

You’ll often use an abstract class when you use nouns to describe the is-a relationship between a base class and derived classes.  E.g. Person as an abstract base class and Man and Woman as derived classes.

By contrast, you’ll often use interfaces when you think about verbs that describe things that instances of a class can do.  E.g. IRun interface containing Run method, implemented by Man and Woman, but also Horse classes.

    public abstract class Person
    // ...

    public class Man : Person, IOperateTools, IDriveTractor

    // ...

    public class Woman : Person, IAskForDirections, ICollaborate

#445 – Differences Between an Interface and an Abstract Class

An interface provides a list of members, without an implementation, that a class can choose to implement.  This is similar to an abstract class, which may include abstract methods that have no implementation in the abstract class, but might also include an implementation for some of its members.

One difference is that an abstract class might include some members that are fully implemented in the abstract class.  Interfaces can’t include the implementations of any of their members.  An interface just describes what a class does, while an abstract class may define how something is done.

Another difference is that a class can inherit from multiple interfaces, but can inherit from at most one base class.  Abstract classes allow you to treat an object polymorphically, based on any of the classes in its inheritance chain.  Interfaces let you treat a class polymorphically, based on any of the interfaces it implements.

#444 – Interfaces Can Inherit from Other Interfaces

An interface can inherit from other interfaces.  A class implementing an interface must then implement all members of all interfaces in the inheritance chain.

For example, assume that we have an INameAndMotto interface with Name and Motto properties.

    interface INameAndMotto
    {
        string Name { get; set; }
        string Motto { get; set; }
    }

Now we can inherit this interface when we define the IMoo interface.

    interface IMoo : INameAndMotto
    {
        void Moo();
        List<string> MooLog { get; set; }
    }

Now if we specify that the Cow class inherits from IMoo, it must implement all methods in both IMoo and INameAndMotto.

    public class Cow : IMoo
    {
        public string Name { get; set; }
        public string Motto { get; set; }

        public void Moo()
        {
            Console.WriteLine("Moo");
        }

        public List<string> MooLog { get; set; }
    }


#443 – An Interface Cannot Contain Fields

An interface can contain methods, properties, events or indexers.  It cannot contain fields.

    interface IMoo
    {
        // Methods
        void Moo();

        // Field not allowed - compile-time error
        string Name;

Instead of a field, you can use a property.

    interface IMoo
    {
        // Methods
        void Moo();

        // Name as a property is OK
        string Name { get; set; }

Interfaces don’t allow fields because they consist of a contract that is a list of methods, whose implementation is provided by a class. Properties are implemented as methods (get and set accessors), so they fit this model.  But fields are just data locations, so it doesn’t make sense to include them in an interface.

#442 – Explicit Interface Implementation Allows Duplicate Member Names

Let’s assume that a class implements more than one interface and there is a particular member that exists in both interfaces.  For example, let’s say that the Cow class implements both the IMoo and IMakeMilk interfaces and they each contain a property named Motto whose type is string.

To provide implementations for both IMoo.Motto and IMakeMilk.Motto, the Cow class must implement the interfaces explicitly, to distinguish between the two properties.

    public class Cow : IMoo, IMakeMilk
    {
        string IMoo.Motto
        {
            get { return "I moo because I want attention"; }
        }

        string IMakeMilk.Motto
        {
            get { return "Everyone should drink a little milk every day"; }
        }

        // Other Cow stuff
    }

We now must access these properties through their corresponding interfaces.

            Cow bossie = new Cow("Bossie", 12);

            // NOTE: bossie.Motto does not exist

            IMoo mooing = bossie;
            Console.WriteLine(mooing.Motto);

            IMakeMilk milking = bossie;
            Console.WriteLine(milking.Motto);

#441 – Implementing Interface Members Explicitly

When you implement interface members in a class, the members are normally accessible via either a reference to the class or a reference to the interface.

Cow bossie = new Cow("Bossie", 5);

bossie.Moo();

IMoo mooer = bossie;
mooer.Moo();

If you want interface members to be accessible only via the interface, you can implement an interface member explicitly, by prefixing the member name with the name of the interface.

    public class Cow : IMoo
    {
        void IMoo.Moo()
        {
            Console.WriteLine("Moo");
        }
    }

You can now only call this member using an interface variable.

            Cow bossie = new Cow("Bossie", 12);

            // Compile error: Cow does not contain a definition for 'Moo'
            bossie.Moo();

            // But we CAN access via IMoo
            IMoo mooStuff = bossie;
            mooStuff.Moo();

#440 – A Class Can Implement More than One Interface

It’s possible for a class to implement more than one interface.

For example, a Cow class might implement both the IMoo and the IMakeMilk interfaces.  Multiple interfaces are listed after the class declaration, separated by commas.

    public class Cow : IMoo, IMakeMilk
    {
        public void Moo() { // do mooing here }
        public double Milk() { // do milking here }
    }

You can now use an instance of the Cow class to access members of either interface.

            Cow bossie = new Cow("Bossie", 12);

            // Call both IMoo and IMakeMilk methods
            bossie.Moo();                        // IMoo.Moo
            double numGallons = bossie.Milk();   // IMakeMilk.Milk

We can also set interface variables of either interface type to refer to an instance of a Cow.

            IMoo mooStuff = bossie;
            IMakeMilk milkStuff = bossie;

            mooStuff.Moo();
            numGallons = milkStuff.Milk();

#438 – Benefits of Using Interfaces

You might wonder why you’d define an interface, have a class implement that interface and then access the class through the interface instead of just using the class directly.

One benefit of interfaces is that it allows you to treat different types of objects in the same way, provided that they implement a common interface.

For example, assume that we have Dog, Seal and DrillSergeant classes, all of which implement the IBark interface (which contains a Bark method).  We can now store a collection of instances of these classes and ask all objects in our collection to Bark by using the IBark interface.

            Dog kirby = new Dog("Kirby", 12);
            Seal sparky = new Seal("Sparky");
            DrillSergeant sarge = new DrillSergeant("Sgt. Hartman", "Tough as nails");

            List<IBark> critters = new List<IBark>() { kirby, sparky, sarge };

            // Tell everyone to bark
            foreach (IBark barkingCritter in critters)
            {
                barkingCritter.Bark();
            }


#437 – Access Interface Members through an Interface Variable

Once a class implements a particular interface, you can interact with the members of the interface through any instance of that class.

            Cow bossie = new Cow("Bossie", 5);

            // Cow implements IMoo, which includes Moo method
            bossie.Moo();

You can also declare a variable whose type is an interface, assign it to an instance of any class that implements that interface and then interact with members of the interface through that interface variable.

            // bossie is a Cow, which implements IMoo, so we can point IMoo variable at her
            IMoo mooer = bossie;
            mooer.Moo();

In either case, we end up calling the same Moo method.

Notice that we can’t access members of Cow that aren’t part of IMoo using this interface variable.

Even though MakeSomeMilk is a public method in the Cow class, we can’t access it via IMoo.

#436 – The Implementation of an Interface Can Be a Subset of the Class

When a class implements an interface, it is declaring that it implements all members of the interface.  Client code can interact with an instance of the class through the members of the interface.  It can also interact with class members that are not part of the interface.

For example, assume that the Cow class implements the IMoo interface, which contains the Moo method.  Client code can invoke the Moo method on instances of the Cow class, since it implements IMoo.

            Cow bossie = new Cow("Bossie", 5);

            // Invoke IMoo.Moo
            bossie.Moo();

Clients can also call methods that are not part of the IMoo interface.

            // Call methods and set properties that are NOT part of IMoo
            bossie.MakeSomeMilk();
            bossie.Motto = "Docile but still a maverick";

Follow

Get every new post delivered to your Inbox.

Join 43 other followers