Não posso simplesmente usar todos os métodos estáticos?

63

Qual é a diferença entre os dois métodos UpdateSubject abaixo? Eu senti que usar métodos estáticos é melhor se você quiser apenas operar nas entidades. Em quais situações devo usar métodos não-estáticos?

public class Subject
{
    public int Id {get; set;}
    public string Name { get; set; }

    public static bool UpdateSubject(Subject subject)
    {
        //Do something and return result
        return true;
    }
    public bool UpdateSubject()
    {
        //Do something on 'this' and return result
        return true;
    }
}

Eu sei que vou estar recebendo muitos chutes da comunidade para esta pergunta realmente chata, mas eu não pude deixar de perguntar isso.

Isso se torna impraticável quando se trata de herança?

Atualização:
Está acontecendo no nosso local de trabalho agora. Estamos trabalhando em um aplicativo web asp.net de 6 meses com 5 desenvolvedores. Nosso arquiteto decidiu usar todos os métodos estáticos para todas as APIs. Seu raciocínio, sendo métodos estáticos, é leve e beneficia os aplicativos da web, mantendo a carga do servidor baixa.

    
por Alexander 03.08.2011 / 01:20
fonte

10 respostas

83

Eu irei com os problemas mais óbvios dos métodos estáticos com os parâmetros "this" explícitos:

  1. Você perde o despacho virtual e, subsequentemente, o polimorfismo. Você nunca pode substituir esse método em uma classe derivada. É claro que você pode declarar um método new ( static ) em uma classe derivada, mas qualquer código que o acessa deve estar ciente da hierarquia de classes inteira e fazer a verificação explícita e conversão, que é precisamente o que a OO deve evite .

  2. Classificando uma extensão de # 1, não é possível substituir instâncias da classe por uma interface , porque as interfaces (na maioria das linguagens) não podem declarar static métodos.

  3. A verbosidade desnecessária. Qual é mais legível: Subject.Update(subject) ou apenas subject.Update() ?

  4. Verificação de argumentos. Novamente depende da linguagem, mas muitos irão compilar uma verificação implícita para garantir que o argumento this não seja null para evitar que um erro de referência nula crie condições de tempo de execução inseguras (tipo de saturação de buffer). Não usando métodos de instância, você teria que adicionar essa verificação explicitamente no início de cada método.

  5. É confuso. Quando um programador normal e razoável vê um método static , ele naturalmente assume que ele não requer uma validade instância (a menos que seja preciso várias instâncias, como um método de comparação ou igualdade, ou espera-se que seja capaz de operar com null de referências). Ver os métodos estáticos usados desta maneira nos levará a uma tomada dupla ou talvez tripla, e depois da 4ª ou 5ª vez estaremos estressados e zangados, e Deus te ajude se soubermos o endereço de sua casa.

  6. É uma forma de duplicação. O que realmente acontece quando você invoca um método de instância é que o compilador ou tempo de execução procura o método na tabela de métodos do tipo e invoca-o usando this como argumento. Você está basicamente reimplementando o que o compilador já faz. Você está violando DRY , repetindo o mesmo parâmetro várias vezes em diferentes métodos quando não é necessário.

É difícil conceber qualquer razão boa para substituir os métodos de instância por métodos estáticos. Por favor, não faça isso.

    
por 03.08.2011 / 02:06
fonte
12

Você descreveu exatamente como você faz o OOP em C, no qual apenas métodos estáticos estão disponíveis, e "this" é um ponteiro de struct. E sim, você pode executar o polimorfismo de tempo de execução em C especificando um ponteiro de função durante a construção para ser armazenado como um elemento da estrutura. Os métodos de instância disponíveis em outras linguagens são apenas açúcar sintático que basicamente faz exatamente a mesma coisa sob o capô. Algumas linguagens, como python, estão na metade do caminho, onde o parâmetro "self" é explicitamente listado, mas a sintaxe especial para chamar ele trata de herança e polimorfismo para você.

    
por 03.08.2011 / 05:20
fonte
10

O problema com o método estático vem no momento em que você precisa de uma subclasse.

Os métodos estáticos não podem ser substituídos em subclasses, portanto, suas novas classes não podem fornecer novas implementações dos métodos, tornando-as menos úteis.

    
por 03.08.2011 / 01:30
fonte
7

Se você declarar um método static , não precisará instanciar um objeto da classe (usando a palavra-chave new ) para executar o método. No entanto, você não pode referir-se a qualquer variável de membro a menos que elas também sejam estáticas, caso em que aquelas variáveis de membros pertencem à classe, não um objeto instanciado específico da classe .

Posto de outra forma, a palavra-chave static faz com que uma declaração faça parte da definição de classe, então torna-se um único ponto de referência em todas as instâncias da classe (objetos instanciados da classe) .

Segue-se, então, que se você deseja várias cópias em execução de sua classe e não deseja que o estado (variáveis de membro) seja compartilhado entre todas as cópias em execução (ou seja, cada objeto possui seu próprio estado exclusivo) , então você não pode declarar essas variáveis de membro estáticas.

Em geral, você deve usar static classes e métodos somente quando estiver criando métodos utilitários que aceitem um ou mais parâmetros e retornar um objeto de algum tipo, sem efeitos colaterais (ou seja, mudanças nas variáveis de estado na classe)

    
por 03.08.2011 / 01:29
fonte
3

A razão pela qual as pessoas argumentam que 'métodos estáticos mostram design ruim' não é necessariamente devido aos métodos, é na verdade dados estáticos, implícitos ou explícitos. Por implícito quero dizer qualquer estado no programa que não está contido no valor de retorno (s) ou parâmetros. Modificar estado em uma função estática é um retrocesso para programação procedural. No entanto, se a função não modificar o estado ou delegar a modificação de estado às funções do objeto componente, na verdade é mais um paradigma funcional do que procedimental.

Se você não está mudando de estado, os métodos e classes estáticos podem ter muitos benefícios. Isso torna muito mais fácil garantir que um método seja puro e, portanto, livre de efeitos colaterais e que quaisquer erros sejam totalmente reproduzíveis. Ele também garante que diferentes métodos em vários aplicativos usando uma biblioteca compartilhada possam ter certeza de que obterão os mesmos resultados, considerando a mesma entrada, facilitando muito o rastreamento de erros e o teste de unidade.

Em última análise, não há diferença na prática entre objetos superdimensionados comumente vistos como 'StateManager' e dados estáticos ou globais. O benefício dos métodos estáticos usados corretamente é que eles podem indicar a intenção do autor de não modificar o estado para revisores posteriores.

    
por 29.02.2012 / 04:51
fonte
2

Você está basicamente derrotando o ponto inteiro dos objetos quando faz isso. Há uma boa razão para termos mudado muito do código processual para o código orientado a objetos.

Eu NUNCA declararia um método estático que tomava o tipo de classe como um parâmetro. Isso apenas torna o código mais complexo sem ganho.

    
por 03.08.2011 / 04:05
fonte
2

Esta é uma pergunta muito interessante que tende a ter respostas muito diferentes dependendo da comunidade que você está perguntando. Outras respostas parecem ser C # ou java bias: uma linguagem de programação que é (principalmente) pura orientada a objetos e tem uma espécie de visão idiomática do que é a orientação a objetos.

Em outras comunidades, como C ++, a orientação a objetos é interpretada com mais liberalidade. Alguns especialistas sabem que estudam o assunto e, na verdade, concluem que funções gratuitas melhoram o encapsulamento (a ênfase é minha):

We've now seen that a reasonable way to gauge the amount of encapsulation in a class is to count the number of functions that might be broken if the class's implementation changes. That being the case, it becomes clear that a class with n member functions is more encapsulated than a class with n+1 member functions. And that observation is what justifies my argument for preferring non-member non-friend functions to member functions

Scott Meyers

Para quem não conhece a terminologia do C ++:

  • função de membro = método
  • função não membro = método estático
  • não amigo = use apenas a API pública
  • função não-membro não-membro = método estático que usa apenas API pública

Agora, para responder à sua pergunta:

Can't I just use all static methods?

Não, você não deve usar sempre métodos estáticos.

Mas você deve usá-los sempre que precisar usar apenas a API pública de uma classe.

    
por 30.07.2013 / 17:53
fonte
1

Dependendo do idioma e do que você está tentando fazer, a resposta pode ser que não há muita diferença, mas a versão static tem um pouco mais de confusão.

Como sua sintaxe de exemplo sugere Java ou C #, acho que o Thorbjørn Ravn Andersen está certo em apontar o problema predominante (com ligação tardia). Com um método estático, não há nenhum parâmetro "especial" para a vinculação tardia a ser baseada, então você não pode ter ligação tardia.

Na verdade, um método estático é apenas uma função em um módulo, esse módulo tem o mesmo nome da classe - não é realmente um método OOP.

    
por 03.08.2011 / 01:49
fonte
1

Há muitas ótimas respostas aqui, e elas são muito mais perspicazes e informadas do que qualquer coisa que eu possa encontrar como resposta, mas sinto que há algo que não está sendo tratado:

"Nosso arquiteto decidiu que usamos todos os métodos estáticos para todas as APIs. Seu raciocínio, sendo métodos estáticos, é leve e beneficia os aplicativos da web mantendo a carga do servidor inativa.

(ênfase ousada é minha)

Meu 2c nesta parte da pergunta é:

Teoricamente, o que é dito é verdade: chamar um método estático tem apenas a sobrecarga de realmente invocar esse método. Chamar um método não estático (instância) tem a sobrecarga extra de primeiro instanciar o objeto e, em algum momento, destruir a instância (manualmente ou por meio de alguma forma de coleta de lixo automática, dependendo da plataforma usada).

O jogo um pouco do advogado do diabo sobre isso: podemos ir ainda mais longe e dizer coisas como:

  • isso pode se tornar muito ruim se uma instância for criada para cada invocação do método (instância) (em vez de apenas deixá-la estática e chamá-la assim)

  • dependendo da complexidade do construtor, do tipo hyerarchy, de outros membros da instância e de outros fatores desconhecidos, a sobrecarga extra da chamada do método não estático pode variar e se tornar realmente grande

Na verdade, IMHO, os pontos acima (e a abordagem geral de "vamos usar a estática porque eles são mais rápidos") são argumentos / avaliações do homem palha:

  • se o código for bom e, mais específico para esse argumento, se as instâncias forem criadas somente quando necessário (e destruídas de maneira ideal), você não obterá nenhuma sobrecarga extra usando os métodos de insance. quando apropriado (porque se você criar apenas os objetos necessários, eles teriam sido criados mesmo se esse método fosse declarado como estático em algum lugar onde = mesma sobrecarga de instanciação)

  • abusando desta declaração de métodos estáticos, é possível esconder alguns problemas com seu código em relação a como as instâncias são criadas (já que o método é estático, um código de instanciação incorreto pode passar despercebido até mais tarde, e isso nunca Boa).

por 30.07.2013 / 16:57
fonte
-3

em Java ...

Os métodos estáticos não são sobrescritos, mas estão ocultos e, portanto, seria uma grande diferença (problema?) no caso de estender a classe.

Por outro lado, notei que os programadores Java têm uma tendência a pensar que tudo tem que ser objeto, sem realmente entender o porquê, e eu discordo.

Estático deve ser usado para código específico para a classe. Estático não funciona bem com herança.

alguns bons exemplos de uso de métodos estáticos são funções independentes sem efeitos colaterais.

veja também a palavra-chave sincronizada ...

    
por 17.06.2015 / 17:58
fonte