I see code where an abstract class implements an interface? Why would you do that? Instead of putting abstract members in interface we can directly put them in the interface right ?
Why would one write such code? What is the purpose or need?
I see code where an abstract class implements an interface? Why would you do that? Instead of putting abstract members in interface we can directly put them in the interface right ?
Why would one write such code? What is the purpose or need?
An interface is simply a contract to other code. An abstract class on the other hand, can be much more. They can:
One good example of a use case for this is found in the template method pattern. You could have an interface for a command:
public interface IMyCommand
{
void Execute();
}
And you have a set of commands that follows a certain sequence. To enforce that, you could have them derive from an abstract base class:
public abstract class MyTemplateClass : IMyCommand
{
public void Execute()
{
MyProcessFirst();
MyProcessSecond();
}
protected abstract void MyProcessFirst();
protected abstract void MyProcessSecond();
}
Now you can have objects that follow the template method derive from the abstract base class, and others just implement the interface.
Instead of putting abstract members in interface we can directly put them in the interface right ?
Not with an implementation we can't.
Because we can have part of the implementation in the abstract class, we can get all of the advantages of reuse.
We could though ask the opposite; why not just have the abstract class and no interface.
Often, especially with private or internal combinations of abstract class and interface it would indeed be an improvement to do this. But there are still some advantages to interfaces that abstract classes don't have.
An obvious one is if we have, or are likely to have, implementations that aren't derived from that abstract class. Another is to take advantage of variance in the interface, which the class can't do.
Even if we don't have any cases now that implement the interface but not via the abstract class, it's worth considering if we might, if the interface is public (YAGNI applies very differently to public interfaces where it will be a breaking change to remove anything).
Related to that, it can be a useful combination to have a public interface that client code may implement as well as your code, and an abstract class used in the implementations you provide, because it contains commonality to your implementations that wouldn't necessarily be common to other people's implementations. Perhaps you would allow other people to inherit from it too, without insisting on it, or perhaps you would have only internal
constructors so only your code can use it.
One possible reason i see is, if you implement an interface with abstract class you don't need to implement all methods in the abstract class. You can leave the those methods with just declaration(indirectly you are implementing it, but just deferring the implementation).
Suppose you're developing a popular library that has an interface IStream
, which is used in various APIs throughout your library. IStream
has the following methods:
int Read(byte[] buffer, int offset, int count);
void Write(byte[] buffer, int offset, int count);
But rather than have people implement that interface directly, you highly recommend that they inherit from your abstract class, Stream
, which implements that interface as follows:
public abstract int Read(byte[] buffer, int offset, int count);
public abstract void Write(byte[] buffer, int offset, int count);
Lots of people follow your recommendation, but not everybody reads the documentation, so some implement IStream
directly.
Now the next version of your library comes out. You're really excited, because you're going to implement asynchronous operations for your streams. So you add the following methods to IStream
:
Task<int> ReadAsync(byte[] buffer, int offset, int count);
Task WriteAsync(byte[] buffer, int offset, int count);
Now you go to update your abstract class to make it compile. You could make the new methods abstract, but as it turns out, there's a not-completely-insane alternative (error handling omitted):
public virtual Task<int> ReadAsync(byte[] buffer, int offset, int count)
{
return Task.Run(() => this.Read(buffer, offset, count));
}
public virtual Task WriteAsync(byte[] buffer, int offset, int count)
{
return Task.Run(() => this.Write(buffer, offset, count);
}
For lots of real-world stream types, there's usually going to be a different way to handle asynchronous reads and writes, and it's probably zillions of times more efficient than this (which is why it's virtual instead of sealed), but this may just be good enough for most consumers.
Now let's look at the two groups of people. The folks who inherit from the abstract class automatically get the implementation of IStream.ReadAsync
and IStream.WriteAsync
without having to write any more code themselves. Their streams can also be used as-is in your new fancy asynchronous APIs without them having to do any work, and there's a chance that it just might not suck.
The folks who implemented the interface, on the other hand, now have to deal with writing their own implementations of those IStream
methods, even if they have no interest in using asynchronous APIs. Maybe they throw NotSupportedException to make the errors go away. Now they need to make sure they don't call into anything that might have a chance of calling into IStream.ReadAsync
or IStream.WriteAsync
. They're not happy. They did this to themselves by not following your recommendations, but still, it's hard not to sympathize.
This is a big advantage to having an abstract class implement an interface. In fact, some might argue that IStream
shouldn't exist at all for exactly this reason, and the abstract Stream
class should just show up in all the APIs where IStream
would have instead. Blind guess: maybe that's exactly why there's System.IO.Stream, but no System.IO.IStream
. Though I'd personally have preferred to have IStream
around.