Say you need some gate keepers:
public interface IGateKeeper
{
/// <summary>
/// Check if the given id is allowed to enter.
/// </summary>
/// <param name="id">id to check.</param>
/// <param name="age">age to check</param>
/// <returns>A value indicating whether the id is allowed to enter.</returns>
bool CanEnter(string id, int age);
... other deep needs ...
}
You may have a solid implementation of it to test the majority at the entrance of your bar:
public class MajorityGateKeeper : IGateKeeper
{
public virtual bool CanEnter(string id, int age)
{
return age >= 18;
}
... other deep implementation ...
}
And also have an implementation for the VIP room:
public class VipGateKeeper : MajorityGateKeeper
{
public override bool CanEnter(string id, int age)
{
// Do the majotity test and check if the id is VIP.
return base.CanEnter(id, age) && (id == "Chuck Norris");
}
}
And break it in a second:
public class DrunkGateKeeper : VipGateKeeper
{
public override bool CanEnter(string id, int age)
{
return true;
}
}
The DrunkGateKeeper is a VipGateKeeper so you can hide it's drunk (cast to VipGateKeeper). But it do a terrible job.
var gk = (VipGateKeeper) new DrunkGateKeeper();
var canEnter = gk.CanEnter("Miley Cyrus", 16); // true (sic)
If you make the VipGateKeeper sealed you are sure that it can't be drunk: an object of type VipGateKeeper is a VipGateKeeper nothing more.