Crie métodos que não dependem dos campos da instância, estáticos?

19

Recentemente, comecei a programar no Groovy para uma estrutura de teste de integração, para um projeto Java. Uso o Intellij IDEA com o plug-in Groovy e fico surpreso ao ver como um aviso para todos os métodos que não são estáticos e não dependem de nenhum campo de instância. Em Java, no entanto, isso não é um problema (pelo menos do ponto de vista do IDE).

Todos os métodos que não dependem de nenhum campo de instância devem ser transformados em funções estáticas? Se for verdade, isso é específico do Groovy ou está disponível para OOP em geral? E porque?

m3th0dman
fonte
Esses métodos chamam outros métodos de instância? Ou eles literalmente não têm nada a ver com um objeto dessa classe? Você pode dar um exemplo?
quer

Respostas:

26

Observe que a IDEA também tem essa inspeção para Java, chamada de Método pode ser 'estática' ,

Esta inspeção relata quaisquer métodos que possam ser tornados estáticos com segurança. Um método pode ser estático se não referenciar nenhum dos métodos não estáticos e campos não estáticos de sua classe e não for substituído em uma subclasse ...

O problema é que, para o código Java, essa inspeção é desativada por padrão (o programador pode ativá-la a seu critério). A razão para isso é mais provável que a validade / utilidade dessa inspeção possa ser contestada, com base em algumas fontes bastante autoritativas.

Para começar, o tutorial oficial sobre Java é bastante restritivo quando os métodos devem ser estáticos:

Um uso comum para métodos estáticos é acessar campos estáticos.

Dado acima, pode-se argumentar que ativar a inspeção mencionada por padrão não está de acordo com o uso recomendado do modificador estático em Java.

Além disso, existem algumas outras fontes que chegam a sugerir uma abordagem criteriosa sobre o uso de idéias que estão por trás dessa inspeção ou mesmo a desencorajar.

Veja, por exemplo, o artigo Java World - Mr. Happy Object ensina métodos estáticos :

Qualquer método que seja independente do estado da instância é um candidato a ser declarado como estático.

Observe que eu digo "candidato a ser declarado como estático". Mesmo no exemplo anterior, nada obriga a declarar instances()como estático. Declarar como estático apenas torna mais conveniente chamar, pois você não precisa de uma instância para chamar o método. Às vezes, você terá métodos que parecem não depender do estado da instância. Você pode não querer tornar esses métodos estáticos. Na verdade, você provavelmente só desejará declará-las como estáticas se precisar acessá-las sem uma instância.

Além disso, mesmo que você possa declarar um método como estático, talvez não queira, devido aos problemas de herança que ele interpõe no seu design. Dê uma olhada em "Design Orientado a Objetos Efetivo" para ver alguns dos problemas que você enfrentará ...

Um artigo no blog de testes do Google chega ao ponto de afirmar que os métodos estáticos são "Morte à testabilidade" :

Vamos fazer um exercício mental. Suponha que seu aplicativo não tenha senão métodos estáticos. (Sim, é possível escrever um código assim, é chamado de programação procedural.) Agora, imagine o gráfico de chamada desse aplicativo. Se você tentar executar um método folha, não haverá problemas ao configurar seu estado e afirmar todos os casos de canto. A razão é que um método folha não faz mais chamadas. À medida que você se afasta das folhas e se aproxima do main()método raiz , será cada vez mais difícil estabelecer o estado em seu teste e mais difícil afirmar as coisas. Muitas coisas se tornarão impossíveis de afirmar. Seus testes ficarão progressivamente maiores. Depois de chegar aomain()método que você não tem mais um teste de unidade (como sua unidade é o aplicativo inteiro), agora você tem um teste de cenário. Imagine que o aplicativo que você está tentando testar é um processador de texto. Não há muito que você possa afirmar a partir do método principal ...

Às vezes, um método estático é uma fábrica para outros objetos. Isso exuberante ainda mais o problema de teste. Nos testes, contamos com o fato de podermos conectar objetos de maneira diferente, substituindo dependências importantes por zombarias. Depois que um newoperador é chamado, não podemos substituir o método por uma subclasse. Um chamador de uma fábrica estática está permanentemente ligado às classes de concreto que o método da fábrica estática produziu. Em outras palavras, o dano do método estático está muito além do próprio método estático. A inserção da fiação do gráfico de objetos e o código de construção no método estático é muito ruim, pois a fiação do gráfico de objetos é como isolamos as coisas para testes ...


Veja bem, dado acima, parece natural que a inspeção mencionada esteja desativada por padrão para Java.

Os desenvolvedores de IDE teriam muita dificuldade em explicar por que acham que é tão importante configurá-lo por padrão, contra recomendações e práticas recomendadas amplamente reconhecidas.

Para Groovy, as coisas são bem diferentes. Nenhum dos argumentos listados acima se aplica, particularmente o sobre testabilidade, conforme explicado, por exemplo, no artigo Mocking Static Methods in Groovy no Javalobby:

Se a classe Groovy que você está testando chama um método estático em outra classe Groovy, você pode usar o ExpandoMetaClass, que permite adicionar dinamicamente métodos, construtores, propriedades e métodos estáticos ...

Essa diferença é provavelmente o motivo pelo qual a configuração padrão para a inspeção mencionada é oposta ao Groovy. Enquanto em Java o padrão "on" seria fonte de confusão para os usuários, no Groovy, uma configuração oposta poderia confundir os usuários do IDE.

"Ei, o método não usa campos de instância, por que você não me alertou sobre isso?" Essa pergunta seria fácil de responder para Java (como explicado acima), mas para Groovy, simplesmente não há explicação convincente.

mosquito
fonte
By the way, ReSharper (feito por JetBrains para C # / Visual Studio) sugere a mesma coisa
Konrad Morawski
6
Há uma distinção importante entre métodos estáticos com e sem efeitos colaterais. O extrato do Google realmente aborda o anterior.
Assilias
@assylias Sim, mas também discute como os métodos de fábrica podem dificultar o teste (já que ele une fortemente as dependências do aplicativo). Usar uma estrutura de injeção de dependência é uma das melhores soluções para isso e também resolve muitos outros problemas.
Per Lundberg
5

É difícil imaginar que isso tenha algum efeito discernível no desempenho. O único benefício que posso ver para torná-los staticé que ele fornece uma indicação visual de que o estado da instância não é afetado. Em outras palavras, ele diz à pessoa que está lendo o código-fonte algo ... "interessante" sobre esse método, apenas em virtude de estar lá. A verdadeira questão é: isso esclarece ou confunde? "Por que esse método é estático? É um método de fábrica? É possível chamá-lo sem uma instância de objeto?"

Além disso, algumas pessoas não gostam de métodos estáticos, porque alegam que você não pode zombar deles e, portanto, não são testáveis ​​ou algo nesse sentido. Certamente, se você está tornando estático por qualquer um dos motivos usuais, como fornecer um método de fábrica, por exemplo, então sou a favor. Só não tenho certeza de que tornar métodos estáticos apenas porque eles não tocam no estado da instância é um mandato.

Robert Harvey
fonte
5
Considere que (em Java) um método estático não pode ser substituído. Embora nem sempre seja um problema, significa que algumas subclasses mais tarde não podem alterar essa implementação. Isso não quer dizer que um método estático não seja a resposta certa, mas parte das considerações de design.
2
@ user40980 vale a pena considerar, é verdade, mas também vale a pena considerar que a herança pode ser uma ferramenta desajeitada que é frequentemente mal utilizada, e várias figuras proeminentes argumentam que todas as classes devem ser finalou especificamente projetadas com herança em mente.
Sara
3

Eu acho que é para permitir que uma possível refatoração seja identificada .

Depois que o método se torna estático, fica claro que ele pode ser movido para fora da classe, digamos, para uma classe unity.

Também é fácil transformá-lo em um método de instância de um de seus parâmetros; geralmente é aqui que o código deve estar.

Ian
fonte
-1

Observe que você pode ter classes sem estado que implementam alguma interface (por exemplo java.lang.Runnable- você não pode tornar seus métodos estáticos. Alguns padrões (por exemplo, Estratégia) também podem produzir objetos sem estado que podem até ter vários métodos.

A estática são primos em primeiro grau dos singletons. Será muito difícil mudar de estática para não estática posteriormente - portanto, quando você precisar adicionar um estado, ficará tentado a começar a introduzir variáveis ​​estáticas.

Eugene
fonte
Como isso responde à pergunta?
mosquito
1
por que é difícil passar de um estado para outro? Eu diria que é o contrário. é mais fácil contaminar algo puro do que purificar algo contaminado.
sara