Ao ler sobre quando tornar um método estático ou não, vi um princípio geral, conforme resumido neste post , de que um método só deve ser estático se não modificar um estado e seu resultado depender apenas dos parâmetros fornecidos para isto. No entanto, a resposta mais votada nesta publicação afirma que métodos estáticos devem ser usados sempre que possível. Muitas das respostas deste post dizem que é preciso fazer o que for mais lógico.
No meu caso, tenho ~ 15 métodos em uma classe de utilitário comum porque eles são usados em vários locais e não fazem sentido como membro de qualquer modelo ou modelo de exibição (usando C # MVVM). Existem métodos nulos que interagem com vários componentes de hardware usando seus pacotes (por exemplo, National Instruments, clientes OPC, etc.). Também existem métodos que recebem alguma entrada, fazem um GET ou PUT em nossa API e retornam uma resposta - esses métodos usam HttpClient ou algo semelhante. Esses métodos não são operadores simples na entrada, como Math.Sqrt()
, e não alteram os estados.
Então, esses métodos (e, neste caso, toda a classe) devem ser estáticos? Existe o benefício óbvio de ter uma classe estática com métodos estáticos: é seguro e rápido, porque você não precisa criar um objeto. Além disso, cada um desses métodos estáticos usa mais métodos e classes estáticos para interações de API e hardware. A única desvantagem que vejo é que eu teria que escrever testes de unidade com uma estrutura paga, como o TypeMock Isolator. O custo não é um problema se a resposta é zombar deles usando algo como o TypeMock Isolator ou algum serviço pago semelhante; portanto, se esse for o consenso, tudo bem. Eu só quero tomar uma decisão que seja bem dimensionada e deixe pouca dívida técnica para trás, à medida que criamos novos desenvolvedores e à medida que nosso projeto cresce.
Informe-me se precisar fornecer mais informações para tornar isso mais claro!
fonte
Respostas:
Não. Ou pelo menos, você não deve usá-los diretamente como estática.
Se você está trabalhando com vários componentes de hardware, você está muito muito propensos a querer zombar deles, use os novos, e escolher qual deles você está usando. Isso tudo grita por ter uma interface (ou outra abstração), para que o resto do seu código possa imediatamente ignorar a existência de algum componente de hardware. E a estática na maioria dos idiomas joga muito mal com interfaces (e outros mecanismos de abstração).
fonte
Os conselhos conflitantes que você leu todos fazem sentido de alguma maneira, mas todos eles fazem suposições (diferentes) ou frases ambíguas. É um daqueles "dizendo a mesma coisa com palavras diferentes" tipos de distinções.
Observe a ambiguidade de "modificar um estado". O exemplo a seguir viola essa regra (literalmente), mas preserva o espírito (figurativo) da regra:
Isso modifica o estado do
User
objeto e, de fato, "modifica um estado".No entanto, esse método não depende de um estado interno específico para decidir seu próprio fluxo lógico (por exemplo,
u.Name = currentlySelectedDefaultName()
seria uma violação, pois o nome selecionado é um estado selecionado). E acho que é isso que significa: nenhum estado interno é modificado.Veja o item anterior, este está praticamente dizendo a mesma coisa. O que isso significa é que isto:
não deve ser estático, pois o nome "padrão atual" é um estado e, portanto, não deve ser uma variável / método global.
Pense no que acontece se dois threads separados estiverem em execução: um deles quer usar o padrão "Bob", o outro quer usar o padrão "Jim". Eles acabarão brigando pelo valor, que pode criar problemas de depuração maciços e comportamento inesperado.
Se, no entanto, cada thread tiver seu próprio
DefaultNameSetter
objeto, eles não lutarão pelo mesmo recurso.Isso é meio que impor uma regra por tentativa / falha. Podemos definir esse método como estático?
=>
bom! Mantenha assim!=>
Isso prova que o código depende de um valor não estático em algum lugar e, portanto, não deve ser tornado estático.Para citar indiretamente Jeff Goldblum em Jurassic Park , você não deve discutir a necessidade de fazer algo apenas provando que isso pode ser feito.
Novamente, a abordagem não está necessariamente (ou sempre) errada, mas assume cegamente que os métodos já foram escritos para serem tão independentes do estado quanto logicamente possível, o que simplesmente não é o caso.
Mesmo se você se inscrever nessa abordagem metodológica, ainda poderá aplicá-la quando um projeto não estiver mais em desenvolvimento. Se o projeto ainda estiver em desenvolvimento, os métodos atuais podem ser espaços reservados para a futura implementação. Pode ser possível tornar
Foo()
estática hoje, mas não amanhã, se a lógica dependente do estado simplesmente ainda não tiver sido implementada.Bem, eles não estão errados; mas isso não é apenas uma pequena reformulação de dizer "faça a coisa certa"? Esse não é um conselho realmente útil, a menos que você já saiba quando usar estática e quando evitá-la. É uma pegadinha 22.
Então, quando você deve usar estática?
Como você notou, nem todos concordam com a regra, ou pelo menos em como formular a regra. Vou adicionar outra tentativa aqui, mas esteja ciente de que isso está criando efetivamente outro padrão :
Tenha isso em mente.
A estática são verdades universais.
Esse é o objetivo de um espaço para nome global: coisas que estão corretas em toda a camada do aplicativo.
Há um argumento de declive escorregadio aqui. Alguns exemplos:
Este é um exemplo muito claro. A configuração do aplicativo implica inerentemente que a configuração é global para o aplicativo e, portanto, é garantido um método estatístico.
Este método é universalmente correto. Não importa quais datas você está comparando. O método não se importa com o significado das datas. Sejam datas de emprego, datas de contrato, ... não importa para o algoritmo do método.
Observe a semelhança semântica entre contextual e guiada pelo estado . Ambos os tipos se referem a um estado "não universal". Isso prova que as diferenças contextuais, portanto, dependem do estado e não são adequadas para serem tornadas estáticas.
Esta é uma verdade universal. O mesmo processo de criação é usado em todo o aplicativo.
No entanto, esta linha pode ficar embaçada:
Do ponto de vista técnico, nada mudou. Gerente (e zeladores) são criados da mesma maneira em todo o aplicativo. No entanto, isso criou sutilmente um estado (gerente / zelador), que diminui lenta mas firmemente o quão universal é realmente a verdade.
Isso pode ser feito? Do ponto de vista técnico; sim .
Isso deveria ser feito? É uma questão de saber se você está discutindo o princípio puro ou se leva em consideração que é necessário fazer compromissos para não se esforçar sem sentido pela perfeição lógica. Então, eu diria que se não criar um problema maior do que o problema pretende resolver .
À medida que as opções se expandem (gerentes, zeladores, contadores, vendedores, ...), o problema aumenta. Para um problema suficientemente grande, é desejável um padrão de fábrica .
Se você tiver apenas duas opções e não tiver motivos para suspeitar que a lista de opções aumentará, é possível argumentar que os métodos de criação estáticos são suficientes. Alguns podem discordar, e eu também entendo o que eles querem dizer. Mas eu costumo ser prático e não excessivamente perfeccionista em minha abordagem.
fonte
Métodos estáticos que afetam o estado ao qual estão diretamente acoplados são uma péssima idéia. Eles levam ao estado global - "ação assustadora à distância" - questões, código de espaguete e similares. Eles são difíceis de testar, depurar e manter. Minha leitura da resposta mais votada não encoraja nada disso, então está tudo bem.
Depende. Vamos dar um exemplo dos " métodos nulos que interagem com vários componentes de hardware usando seus pacotes ". Esses métodos podem ser estáticos, mas apenas se forem dissociados desses pacotes. Uma maneira de conseguir isso é passar esses pacotes como parâmetros. Deseja testar o método sem o hardware? Fácil, passe um pacote fictício e zombado que registra ações, em vez de acessar o hardware através do parâmetro O mesmo se aplica aos métodos HTTP; desde que o meio real de acessar a API seja transmitido como parâmetro, também.
Mas, você realmente está conseguindo algo dessa maneira ao criar uma instância e injetar esses pacotes, classes HTTP etc. no momento da construção? Provavelmente não. Claro, eles são métodos estáticos, portanto você não precisa de uma instância. Mas você tem a complexidade adicional de precisar expor todos esses pacotes, etc., por todo o código, a fim de passá-los como parâmetros. Muitas vezes, é muito mais fácil criar uma única instância e distribuí-la.
fonte
IUtilityMethods
que passar várias instâncias que precisam ser passadas para funções estáticas.O que recomendo e o que estou usando em minha equipe é usar métodos / classes estáticos, se houver uma necessidade real. Não deve ser a primeira opção para usar métodos / classes estáticos. Tem que ser uma boa razão para isso. Muitos desenvolvedores vêem que a opção estática é mais rápida e, portanto, mais barata. Mas isso é talvez no começo. O custo é criar testes de unidade mais complicados e sem a capacidade de usar contratos (interfaces) com várias implementações. Para os métodos / classes que interagem com o hardware. Estes não devem ser estáticos. Primeiro e para a maioria, não há razão. Segundo, é necessário zombar dessas classes em testes de unidade para obter um código de teste mais simples. Terceiro, é possível substituir a implementação no futuro.
fonte
As funções estáticas são mais desafiadoras quando você deseja permitir o acesso múltiplo em paralelo.
Por exemplo, é perfeitamente razoável, e provavelmente uma boa idéia, permitir que várias chamadas HTTP sejam executadas ao mesmo tempo. Com um objeto de instância, você pode facilmente manter um estado diferente para essas chamadas - os cabeçalhos, códigos de resultado, buffers, etc.
Com um único método estático, você pode criar uma instância interna para manter esse estado. Ou você sincroniza tudo (estou usando a terminologia Java, YMMV), que é suscetível a erros. Ou use uma fila. De qualquer forma, sem um trabalho de pés sofisticado, você perde a capacidade de correr em paralelo. Se uma chamada HTTP atolar devido a uma falha na rede, todas as outras terão que esperar.
O mesmo para o seu hardware - em alguns casos, pode fazer sentido permitir o acesso em paralelo.
Por esses motivos, discordo da resposta de 8 anos que você citou.
fonte