Еще в 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контексте.