Qual é a diferença entre os dois métodos UpdateSubject abaixo? Eu senti que usar métodos estáticos é melhor se você apenas deseja operar com as 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 receber muitos chutes da comunidade por essa pergunta realmente irritante, mas não consegui parar de perguntar.
Isso se torna impraticável quando se trata de herança?
Atualização:
Está acontecendo em nosso local de trabalho agora. Estamos trabalhando em um aplicativo da 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 como métodos estáticos é leve e beneficia os aplicativos da web, mantendo a carga do servidor baixa.
object-oriented
static-methods
Alexander
fonte
fonte
Respostas:
Vou abordar os problemas mais óbvios dos métodos estáticos com parâmetros explícitos "this":
Você perde o despacho virtual e, posteriormente, 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 de toda a hierarquia de classes e fazer verificação e conversão explícitas, que é precisamente o que o OO deve evitar .Como uma extensão nº 1, não é possível substituir instâncias da classe por uma interface , porque as interfaces (na maioria dos idiomas) não podem declarar
static
métodos.A verbosidade desnecessária. O que é mais legível:
Subject.Update(subject)
ou apenassubject.Update()
?Verificação de argumento. Novamente depende da linguagem, mas muitos compilarão uma verificação implícita para garantir que o
this
argumento não sejanull
para impedir que um bug de referência nulo crie condições inseguras de tempo de execução (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.É confuso. Quando um programador normal e razoável vê um
static
método, ele naturalmente assume que não requer uma instância válida (a menos que instale várias instâncias, como um método de comparação ou igualdade, ou se possa operar comnull
referências) . Ver métodos estáticos usados dessa maneira nos fará fazer uma captura dupla ou tripla, e após a quarta ou quinta vez estaremos estressados e com raiva, e que Deus o ajude se soubermos o seu endereço residencial.É uma forma de duplicação. O que realmente acontece quando você chama um método de instância é que o compilador ou o tempo de execução consulta o método na tabela de métodos do tipo e o invoca usando
this
como argumento. Você está basicamente reimplementando o que o compilador já faz. Você está violando DRY , repetindo o mesmo parâmetro repetidamente em métodos diferentes quando não é necessário.É difícil conceber qualquer boa razão para substituir métodos de instância por métodos estáticos. Por favor não.
fonte
File
,FileInfo
eDirectoryInfo
(e, de fato, existem bibliotecas que eles se escondem atrás de interfaces que podem então ser injetados conforme necessário e ridicularizado em testes).Você descreveu exatamente como fazer OOP em C, no qual apenas métodos estáticos estão disponíveis, e "this" é um ponteiro de estrutura. E sim, você pode executar o polimorfismo do 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 outros idiomas são apenas açúcar sintático que essencialmente faz exatamente a mesma coisa sob o capô. Algumas linguagens, como python, estão no meio do caminho, onde o parâmetro "self" está explicitamente listado, mas uma sintaxe especial para chamá-lo lida com herança e polimorfismo para você.
fonte
obj->type->mthd(obj, ...);
e isso é substancialmente semelhante ao que acontece com o despacho virtual em outros idiomas (mas nos bastidores).O problema com o método estático ocorre no momento em que você precisa de uma subclasse.
Os métodos estáticos não podem ser substituídos nas subclasses; portanto, suas novas classes não podem fornecer novas implementações dos métodos, tornando-os menos úteis.
fonte
Se você declarar um método
static
, não precisará instanciar um objeto da classe (usando anew
palavra - chave) para executar o método. No entanto, você não pode se referir a nenhuma variável de membro, a menos que elas também sejam estáticas; nesse caso, essas variáveis de membro pertencem à classe, não um objeto instanciado específico da classe.Em outras
static
palavras , a palavra - chave faz com que uma declaração faça parte da definição da classe, tornando-se um único ponto de referência em todas as instâncias da classe (objetos instanciados a partir da classe).Conclui-se, então, que se você deseja várias cópias em execução da sua classe e não deseja que o estado (variáveis-membro) seja compartilhado entre todas as suas 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 ao criar métodos utilitários que aceitem um ou mais parâmetros e retornar um objeto de algum tipo, sem efeitos colaterais (ou seja, alterações nas variáveis de estado na classe)fonte
static
significa, ele está perguntando por que não declarar tudo como estático.Subject
- mas como um parâmetro explícito, em vez dothis
parâmetro implícito .this
parâmetro implícito . Há diferenças nas expectativas, mas fora da herança, não há diferença real no que você pode fazer. Por exemplo, esses membros não estáticos podem ser acessados - através do parâmetro explícito.A razão pela qual as pessoas argumentam que 'os métodos estáticos mostram um design ruim' não é necessariamente devido aos métodos, na verdade são dados estáticos, implícitos ou explícitos. Por implícito, quero dizer QUALQUER estado do programa que não esteja contido nos valores ou parâmetros de retorno. Modificar o estado em uma função estática é um retrocesso para a programação procedural. No entanto, se a função não modifica o estado ou delega a modificação do estado nas funções do objeto componente, na verdade, é mais um paradigma funcional do que processual.
Se você não está mudando de estado, métodos e classes estáticos podem ter muitos benefícios. Torna muito mais fácil garantir que um método seja puro e, portanto, livre de efeitos colaterais e quaisquer erros sejam totalmente reprodutíveis. Ele também garante que métodos diferentes em vários aplicativos usando uma biblioteca compartilhada possam ter certeza de que obterão os mesmos resultados com a mesma entrada, facilitando muito o rastreamento de erros e o teste de unidade.
Por fim, não há diferença na prática entre objetos de grandes dimensões 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.
fonte
making ... unit testing much easier.
Não, não vai. Isso torna impossível qualquer código que chame métodos estáticos para teste de unidade , pois você não pode isolá-lo do método estático. Uma chamada para um método estático se torna uma dependência codificada para essa classe.Dependendo do idioma e do que você está tentando fazer, a resposta pode ser que não há muita diferença, mas a
static
versão tem um pouco mais de confusão.Como seu exemplo de sintaxe sugere Java ou C #, acho que Thorbjørn Ravn Andersen está certo ao apontar o problema principal (com ligação tardia). Com um método estático, não há parâmetro "especial" para ligação tardia com base, portanto você não pode ter ligação tardia.
De fato, um método estático é apenas uma função em um módulo, esse módulo tendo o mesmo nome que a classe - não é realmente um método OOP.
fonte
Você está basicamente derrotando todo o objetivo dos objetos quando faz isso. Há uma boa razão para termos mudado de código processual para código orientado a objetos.
Eu nunca declararia um método estático que tomou o tipo de classe como parâmetro. Isso apenas torna o código mais complexo, sem nenhum ganho.
fonte
object
para umstatic
método e retornando um novoobject
. Programadores funcionais fazem isso o tempo todo.Math
classe estática "complexa para nenhum ganho" ou prefere que todos os tipos de números possuam métodos virtuais que definam valor absoluto, negação, adição, quadratura, raízes arbitrárias e assim por diante? Acho que não. os objetos são organizados quando você precisa armazenar um estado mutável oculto no qual você precisa impor alguns invariantes. juntando todos os métodos visíveis que operam em um tipo no próprio tipo, isso é algo que leva a um código complexo e inatingível. Eu concordo com Robert, você pode querer ver como os programadores funcionais funcionam, isso pode ser realmente uma surpresa!Há muitas ótimas respostas aqui, e elas são muito mais perspicazes e informadas do que qualquer outra coisa que eu possa ter como resposta, mas sinto que há algo que não está sendo abordado:
"Nosso arquiteto decidiu usar todos os métodos estáticos para todas as APIs. Seu raciocínio é que os métodos estáticos são leves e beneficiam os aplicativos da web, mantendo a carga do servidor baixa ".
(ênfase em negrito é minha)
Meu 2c nesta parte da pergunta é o seguinte:
Teoricamente, o que se diz é verdade: chamar um método estático só tem a sobrecarga de realmente invocar esse método. Chamar um método não estático (instância) tem a sobrecarga extra de instanciar o objeto primeiro e, em algum momento, destruir a instância (manualmente ou por meio de alguma forma de coleta automática de lixo, dependendo da plataforma usada).
A peça é 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 chamada do método (instance) (em vez de apenas deixá-lo estático e chamá-lo assim)
dependendo da complexidade do construtor, da hierarquia de tipos, de outros membros da instância e de outros fatores desconhecidos, a sobrecarga extra da chamada de 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 são mais rápidos") são argumentos / avaliações:
se o código for bom e, mais específico a esse argumento, se as instâncias forem criadas apenas quando necessário (e destruídas da melhor maneira possível), você não terá nenhuma sobrecarga extra ao usar métodos de seguro quando apropriado (porque se você apenas crie os objetos necessários, eles teriam sido criados mesmo que esse método fosse declarado estático em algum outro local = mesma sobrecarga de instanciação)
abusando da declaração de métodos estáticos dessa maneira, é possível ocultar alguns problemas com seu código em relação à forma como as instâncias são criadas (como o método é estático, um código de instanciação incorreto pode passar despercebido até mais tarde e isso nunca é bom).
fonte
Essa é uma pergunta muito interessante que tende a ter respostas muito diferentes, dependendo da comunidade que você está fazendo. Outras respostas parecem ser c # ou viés java: uma linguagem de programação que é (principalmente) pura orientada a objetos e tem um tipo de visão idiomática do que é orientação a objetos.
Em outras comunidades, como C ++, a orientação a objetos é interpretada com mais liberalidade. Alguns especialistas bem conhecidos estudam o assunto e, na verdade, concluem que funções livres melhoram o encapsulamento (a ênfase é minha):
Para aqueles que não estão familiarizados com a terminologia C ++:
Agora, para responder à sua pergunta:
Não, você nem sempre deve usar métodos estáticos.
Mas você deve usá-los sempre que precisar usar a API pública de uma classe.
fonte
em Java ...
Os métodos estáticos não são substituídos, mas ocultos; portanto, seria uma grande diferença (problema?) No caso de estender a classe.
Por outro lado, notei que os programadores Java tendem a pensar que tudo TEM QUE SER objeto, sem realmente entender o porquê, e eu discordo.
Static deve ser usado para código específico para a classe. Static 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 ...
fonte