Estou muito curioso quanto a pensamentos e melhores práticas do setor em relação a membros estáticos ou classes estáticas inteiras. Existe alguma desvantagem nisso ou ela participa de algum antipadrão?
Eu vejo essas entidades como "classes / membros de utilidade", no sentido de que elas não exigem ou exigem instanciar a classe para fornecer a funcionalidade.
Quais são os pensamentos gerais e as melhores práticas da indústria sobre isso?
Veja o exemplo abaixo de classes e membros para ilustrar o que estou referenciando.
// non-static class with static members
//
public class Class1
{
// ... other non-static members ...
public static string GetSomeString()
{
// do something
}
}
// static class
//
public static class Class2
{
// ... other static members ...
public static string GetSomeString()
{
// do something
}
}
Agradeço antecipadamente!
c#
class-design
Thomas Stringer
fonte
fonte
Respostas:
Em geral, evite a estática - especialmente qualquer tipo de estado estático.
Por quê?
A estática causa problemas com a simultaneidade. Como existe apenas uma instância, ela é compartilhada naturalmente entre a execução simultânea. Esses recursos compartilhados são prejudiciais à programação simultânea e geralmente não precisam ser compartilhados.
A estática causa problemas no teste de unidade. Qualquer estrutura de teste de unidade que valha a pena executa testes simultaneamente. Então você encontra o número 1. Pior ainda, você complica seus testes com todo o material de instalação / desmontagem, e com os truques em que você se encaixa para tentar "compartilhar" o código de instalação.
Há muitas coisas pequenas também. As estáticas tendem a ser inflexíveis. Você não pode fazer interface com eles, não pode substituí-los, não pode controlar o tempo de sua construção, não pode usá-los bem em genéricos. Você não pode realmente versão deles.
Certamente há usos da estática: valores constantes funcionam muito bem. Métodos puros que não se encaixam em uma única classe podem funcionar muito bem aqui.
Mas, em geral, evite-os.
fonte
volatile
. Você simplesmente não obtém garantias do modelo de memória sem dados voláteis, portanto, alterar uma variável em um encadeamento pode não refletir imediatamente ou de maneira alguma.Se a função é "pura", não vejo problemas. Uma função pura opera apenas nos parâmetros de entrada e fornece um resultado com base nisso. Não depende de nenhum estado global ou contexto externo.
Se eu olhar para o seu próprio exemplo de código:
Esta função não aceita nenhum parâmetro. Portanto, provavelmente não é puro (a única implementação pura dessa função seria retornar uma constante). Suponho que este exemplo não seja representativo do seu problema real, estou apenas apontando que essa provavelmente não é uma função pura.
Vamos dar um exemplo diferente:
Não há nada errado com esta função ser estática. Podemos até transformar isso em uma função de extensão, permitindo que o código do cliente se torne ainda mais legível. As funções de extensão são basicamente apenas um tipo especial de funções estáticas.
Telastyn menciona corretamente a simultaneidade como um problema potencial com membros estáticos. No entanto, como essa função não usa o estado compartilhado, não há problemas de simultaneidade aqui. Mil threads podem chamar essa função simultaneamente sem problemas de simultaneidade.
Na estrutura do .NET, os métodos de extensão já existem há algum tempo. O LINQ contém muitas funções de extensão (por exemplo, Enumerable.Where () , Enumerable.First () , Enumerable.Single () , etc.). Nós não vemos isso tão ruim, não é?
O teste de unidade geralmente pode se beneficiar quando o código usa abstrações substituíveis, permitindo que o teste de unidade substitua o código do sistema por um teste duplo. As funções estáticas proíbem essa flexibilidade, mas isso é principalmente importante nos limites da camada de arquitetura, onde queremos substituir, por exemplo, uma camada de acesso a dados real por uma camada de acesso a dados falsa .
No entanto, ao escrever um teste para um objeto que se comporte de maneira diferente, dependendo se algum número é ímpar ou par, não precisamos realmente substituir a
IsOdd()
função por uma implementação alternativa. Da mesma forma, não vejo quando precisamos fornecer umaEnumerable.Where()
implementação diferente para fins de teste.Então, vamos examinar a legibilidade do código do cliente para esta função:
Opção a (com a função declarada como um método de extensão):
Opção b:
A função estática (extensão) torna o primeiro trecho de código muito mais legível e a legibilidade é muito importante; portanto, use funções estáticas sempre que apropriado.
fonte