Еще в 2000-х мой коллега сказал мне, что делать публичные методы виртуальными или абстрактными - это нехорошо.
Например, он считал такой класс не очень хорошо спроектированным:
public abstract class PublicAbstractOrVirtual
{
public abstract void Method1(string argument);
public virtual void Method2(string argument)
{
if (argument == null) throw new ArgumentNullException(nameof(argument));
// default implementation
}
}
Он заявил, что
- разработчик производного класса, который реализует
Method1
и переопределяет,Method2
должен повторить проверку аргумента. - в случае, если разработчик базового класса решит добавить что-то вокруг настраиваемой части
Method1
илиMethod2
позже, он не сможет это сделать.
Вместо этого мой коллега предложил этот подход:
public abstract class ProtectedAbstractOrVirtual
{
public void Method1(string argument)
{
if (argument == null) throw new ArgumentNullException(nameof(argument));
this.Method1Core(argument);
}
public void Method2(string argument)
{
if (argument == null) throw new ArgumentNullException(nameof(argument));
this.Method2Core(argument);
}
protected abstract void Method1Core(string argument);
protected virtual void Method2Core(string argument)
{
// default implementation
}
}
Он сказал мне, что делать открытые методы (или свойства) виртуальными или абстрактными - это так же плохо, как делать открытыми поля. Оборачивая поля в свойства, можно перехватить любой доступ к этим полям позже, если это необходимо. То же самое относится к общедоступным виртуальным / абстрактным членам: их обтекание, как показано в ProtectedAbstractOrVirtual
классе, позволяет разработчику базового класса перехватывать любые вызовы, поступающие в виртуальные / абстрактные методы.
Но я не рассматриваю это как руководство по дизайну. Даже Microsoft не следит за этим: просто посмотрите на Stream
класс, чтобы убедиться в этом.
Что вы думаете об этом руководстве? Это имеет какой-то смысл, или вы думаете, что это слишком усложняет API?
protected
это наиболее полезно, когда вы хотите представить частные члены абстрактного класса производным классам. В любом случае, я не особенно обеспокоен мнением твоего друга; выберите модификатор доступа, наиболее подходящий для вашей конкретной ситуации.
virtual
допускает необязательное переопределение. Ваш метод, вероятно, должен быть публичным, потому что он не может быть переопределен. Создание методовabstract
заставляет вас отвергать их; они, вероятно, должны бытьprotected
, потому что они не особенно полезны вpublic
контексте.