Я думаю, вам нужно разобраться, почему вы не можете разбить иерархию интерфейса.Вы говорите, что иерархия необходима, но некоторые классы не должны будут реализовывать все методы.Это означает, что иерархия не обязательна!
Если IPreferencesReader не нуждается в реализации метода M1, то это действительно не IStart.Контракт, который он заключает, является недействительным.
Помните, что классы могут наследовать несколько интерфейсов.Предполагая, что вы разбиваете иерархию наследования, тогда, если PreferencesReaderBase делает вещи IStop, но не вещи IStart, вы можете объявить это как:
public class PreferencesReaderBase : IPreferencesReader, IStop
Если по какой-либо причине вы не можете разделить этот интерфейсВы могли бы рассмотреть разделение классов реализации.
class Start
{
M1()
{
}
}
class Stop
{
M2()
{
}
}
public class PreferencesReaderBase : IPreferencesReader
{
private Start start = new Start();
private Stop stop = new Stop()
public void M1()
{
this.start.M1();
}
public void M2()
{
this.stop.M2();
}
}
Это, по крайней мере, сохранит основные функциональные классы аккуратными.Каждый класс выполняет одно действие, поэтому Принцип единой ответственности сохраняется.
Тогда толстый интерфейсный класс является просто скелетным классом, который затем может оставаться практически нетронутым в ходе итераций разработки.