Да, это прекрасно. Это пример шаблона Template Method, где вы используете наследование для определения метода, который поддерживает известный «скелет», но может иметь собственную логику.
public abstract class Ancestor
{
protected virtual void CanOverrideThisStep(){...}
protected abstract void MustDefineThisStep();
protected sealed void MustDoExactlyThis(){...}
private void HideThisStepFromEveryone(){...}
public sealed void TemplateMethod()
{
...
CanOverrideThisStep();
...
MustDoExactlyThis();
...
MustDefineThisStep();
...
HideThisStepFromEveryone();
}
}
Приведенные выше наследники Ancestor должны определять тело для MustDefineThisStep () и могут по своему выбору переопределять CanOverrideThisStep (), но не могут касаться MustDoExactlyThis (), HideThisStepFromEveryone или самой движущей функции TemplateMethod. Однако, за исключением HideThisStepFromEveryone, все подметоды доступны дочерним классам, поэтому дочерний объект может использовать MustDoExactlyThis () при реализации MustDefineThisStep ().
Это очень распространено; такие конструкции являются причиной того, что языки OO имеют в своем распоряжении такие модификаторы доступа, подобные этим. Шаблон очень полезен для рабочих процессов, обработки файлов и других задач, которые обычно одинаковы, но имеют немного отличающиеся детали реализации.