Я бы сказал, что ни один метод не является лучше , чем другие. Все они полезны в различных сценариях в зависимости от контекста, в котором они используются.
Если вы реализуете Composite Pattern , и большинство классов будут использовать одну и ту же реализацию, тогда, вероятно, стоит использовать наследование реализации. Это позволит вам уточнить реализацию для тех классов, которые в ней нуждаются, и при этом поделиться кодом для тех, кто этого не делает.
Если вы реализуете Шаблон посетителя , где вполне вероятно, что реализация метода каждого класса будет полностью отличаться, тогда наследование интерфейса может иметь больше смысла. В этом случае реализация базового класса, вероятно, будет использоваться только одним классом.
Я вижу, что ваш средний пример полезен, если вы наследуете проект, который не был разработан с использованием объектно-ориентированных методов. Может быть, вам нужно реорганизовать его при добавлении новых функций, и вы можете использовать его как способ заставить устаревший код взаимодействовать с новым кодом, который использует объектно-ориентированный дизайн. Это скорее компромисс, чем фактическая «лучшая практика», но мы все должны сделать так, чтобы они доставляли продукты ... Если я смогу придумать лучший / более конкретный пример, я опубликую его.