Nos anos 2000, um colega meu me disse que é um anti-padrão tornar os métodos públicos virtuais ou abstratos.
Por exemplo, ele considerou uma classe como esta não bem projetada:
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
}
}
Ele afirmou que
- o desenvolvedor de uma classe derivada que implementa
Method1
e substituiMethod2
deve repetir a validação do argumento. - caso o desenvolvedor da classe base decida adicionar algo à parte personalizável
Method1
ouMethod2
posterior, ele não poderá fazê-lo.
Em vez disso, meu colega propôs essa abordagem:
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
}
}
Ele me disse que tornar os métodos públicos (ou propriedades) virtuais ou abstratos é tão ruim quanto tornar os campos públicos. Ao agrupar campos em propriedades, é possível interceptar qualquer acesso a esses campos posteriormente, se necessário. O mesmo se aplica aos membros públicos / virtuais abstratos: agrupá-los da maneira mostrada na ProtectedAbstractOrVirtual
classe permite que o desenvolvedor da classe base intercepte todas as chamadas que vão para os métodos virtual / abstrato.
Mas não vejo isso como uma diretriz de design. Até a Microsoft não segue: basta dar uma olhada na Stream
classe para verificar isso.
O que você acha dessa linha de orientação? Isso faz algum sentido ou você acha que está complicando demais a API?
protected
é mais útil quando você deseja expor membros particulares da classe abstrata a classes derivadas. De qualquer forma, não estou particularmente preocupado com a opinião de seu amigo; escolha o modificador de acesso que faz mais sentido para sua situação específica.
virtual
permite a substituição opcional. Seu método provavelmente deve ser público, pois pode não ser substituído. Criar métodosabstract
obriga a substituí-los; provavelmente deveriam serprotected
, porque não são particularmente úteis em umpublic
contexto.