Udostępnij za pośrednictwem


Abstract Class or Interface I

Recently I'm working on designing a set of .Net APIs for external clients to use. One of the decisions I had to make is whether I start with abstract class or interface. For example, should it be:

     public abstract class Foo
    {
        public abstract void Bar();
    }

Or should it be:

     public interface IFoo
    {
        void Bar();
    }

Framework Design Guidelines states you should favor abstract class in most cases. The reason is that abstract class versions better. For example, your client may have an implementation of Foo:

     public class FooImpl : Foo
    {
        public override void Bar()
        {
            // do something.
        }
    }

For the next version, if you decide you need to add another method to Foo and you want to minimize the changes your client has to make, you can add a virtual method instead of an abstract method to your abstract class. For example,

     public abstract class Foo // Version 2
    {
        public abstract void Bar();
        public void Baz() // new method added 
        {
            throw new NotImplementedException();
        }
    }

This way, when user recompiles against the new assembly (Alternatively you can use assembly binding redirect, so that user doesn't need to recompile.), the code can remain unchanged. For interfaces, Framework Design Guidelines states that "The only way to evolve interface-based APIs is to add a new interface with the additional members." (page 78). This is true if external user will implement the interface and you want to provide backward compatibility without user recompiling. Even if you decide adding a new method to an existing interface is ok in your case, for example,

     public interface IFoo
    {
        void Bar();
        void Baz(); // new method
    }

The code that implements IFoo must be changed to:

     public class FooImpl : IFoo
    {
        public void Bar()
        {
            // do something.
        }
        public void Baz()
        {
            throw new NotImplementedException(); // need to implement even if we don’t use it.
        }
    }

Besides versioning advantages, abstract class may have implementations. Depending on situations, this can be convenient.

There are three advantages of using interfaces:

1.       You can have multiple inheritance with Interfaces.

2.       You can make interfaces ComVisible and your APIs will be more accessible to COM users.

3.       Interfaces cannot have implementations and more clearly represent pure contract. Interfaces are better suited to situations that having implementations can be actually bad, for example, in the cases of .Net remoting.

After weighing the advantages, I chose to start with abstract class. In my case, versioning is not really an advantage because we do not expect the user to implement the abstract class. I chose abstract class because it is more flexible. For example, I can define all the methods of the abstract class to be virtual and have a default implementation. For example,

     public abstract class Foo
    {
        public void Bar()
        {
            throw new NotImplementedException();
        }
        public void Baz()
        {
            throw new NotImplementedException();
        }
    }

This way, when I'm still in the process of refining the API, I don't have to constantly changing the classes implementing Foo. Later when the API is being finalized, I can change those methods back to abstract methods. In addition, if it turns out we do need to have an API based on interfaces to accommodate COM clients, it should be straightforward to add an interface wrapper. Here is an example:

     public abstract class Foo
    {
        public abstract void Bar(Baz baz);
    }

    internal class FooImpl : Foo, IFoo
    {
        public override void Bar(Baz baz)
        {
            // my implementation.
        }
        void IFoo.Bar(IBaz bazInterface) // explicit implementation
        {
            Bar((Baz)bazInterface); // simply delegate to the real implementation.
        }
    }

    public interface IBaz
    {
    }

    public abstract class Baz : IBaz
    {
    }

    public interface IFoo
    {
        void Bar(IBaz baz);
    }

This way we can actually have two set of APIs: one set based on interfaces and one set based on abstract classes. .Net user can use the abstract class based APIs and COM user can use the interface based ones. More importantly, I can add the interface support much later without worrying about going through major churns[1].

[1] please see part II for why interface ends up being a better choice after all.

Keywords: .Net, abstract class, interface

Comments

  • Anonymous
    April 07, 2008
    In previous post , I was convinced that abstract class was the right choice for the work I am doing.

  • Anonymous
    February 14, 2012
    Do u agree with the thing that abstract class is faster than Interface.. If so can u explain why...