Since examples from projects depend on the domain, which you have to understand first to be able to understand the example, I will abstract it with a cooking example.
Suppose we want to be able to cook pasta with different sauces: we want to handle pasta independently of its sauce in our source code. A first approach could be that of defining an interface IPasta with a method Cook:
public interface IPasta
{
void Cook();
}
Our client code can then cook the pasta independently from the implementation of it: tomato sauce, pesto sauce? You name it, we can cook it:
...
IPasta pasta = GetPasta();
pasta.Cook();
...
Thinking about the problem more carefully, though, we find out that cooking pasta is always the same process, excluding the point where we want to prepare the sauce.
This means that we have a base algorithm for pasta that we can implement independently from any sauce: boil the water, prepare a sauce, take the pasta out of the pot and merge it with the sauce.
public abstract class Pasta
{
public void Cook()
{
BoilWater();
PrepareSauce();
...
}
protected abstract void PrepareSauce();
private void BoilWater()
{
// Boil some water
}
}
public class PastaWithPestoSauce
{
protected override void PrepareSauce()
{
// Prepare pesto sauce
}
}
And our clients will use it like this:
...
Pasta pasta = GetPasta();
pasta.Cook();
...
So we still have an interface, not in C# sense but in the generic sense of a well known public behavior (the public method Cook of the abstract class), but we also managed to spare some code.