Pergunta

I tendem a declarar como static todos os métodos em uma classe quando essa classe não exige manter o controle de estados internos. Por exemplo, se eu preciso para transformar A em B e não dependem de algum estado interno C que pode variar, eu criar uma transformação estática. Se não houver um estado interno C que eu quero ser capaz de ajustar, então eu adicionar um construtor para definir C e não utilize transformar um estático.

Eu li várias recomendações (incluindo em StackOverflow) não overuse métodos estáticos, mas eu ainda não conseguem entender o que de errado com a regra acima.

Isso é uma abordagem razoável ou não?

Foi útil?

Solução

Existem dois tipos de métodos estáticos comuns:

  • Um método estático "seguro" vai sempre dar a mesma saída para as mesmas entradas. Ele modifica há globals e não chamar qualquer métodos estáticos "inseguros" de qualquer classe. Essencialmente, você está usando um tipo limitado de programação funcional -. Não tenha medo deles, eles estão bem
  • Uma "inseguros" método sofre mutações estáticos estado global, ou proxies para um objeto global, ou algum outro comportamento não-testável. Estes são reminiscências a programação procedural e deve ser reformulado, se possível.

Há alguns usos comuns da estática "inseguros" - por exemplo, no padrão Singleton - mas esteja ciente de que, apesar de todos os nomes bonitos você chamá-los, você está apenas mutação variáveis ??globais. Pense cuidadosamente antes de utilizar estática inseguras.

Outras dicas

Um objeto sem qualquer estado interno é uma coisa suspeita.

Normalmente, objetos estado encapsular e comportamento. Um objeto que só encapsula comportamento é estranho. Às vezes, é um exemplo de Leve ou Flyweight .

Outras vezes, seu design processual feito em uma linguagem objeto.

Este é realmente apenas uma continuação ao grande resposta de John Millikin.


Embora possa ser seguro para fazer métodos apátridas (que são praticamente funções) estático, que por vezes pode levar a acoplamento que é difícil de modificar. Considere que você tem um método estático como tal:

public class StaticClassVersionOne {
    public static void doSomeFunkyThing(int arg);
}

O que você chama como:

StaticClassVersionOne.doSomeFunkyThing(42);

Que é tudo muito bem, e muito conveniente, até que você se deparar com um caso em que você tem que modificar o comportamento do método estático, e achar que você está fortemente ligada ao StaticClassVersionOne. Possivelmente você pode modificar o código e que seria bom, mas se houvesse outros chamadores dependentes do comportamento antigo, eles precisam ser contabilizados no corpo do método. Em alguns casos, esse método corpo pode ficar muito feio ou insustentável se ele tenta equilibrar todos esses comportamentos. Se você dividir os métodos que você pode ter que modificar o código em vários lugares para tomar conta dele, ou fazer chamadas para novas classes.

Mas considere se você tivesse criado uma interface para fornecer o método, e dado que para os chamadores, agora, quando o comportamento tem que mudar, uma nova classe pode ser criada para implementar a interface, que é mais limpo, mais facilmente testado e mais sustentável, e que em vez disso é dado para os chamadores. Neste cenário não precisa as classes que chamam de ser alterada ou até mesmo recompilados, e as mudanças são localizadas.

Pode ou não pode ser uma situação provável, mas acho que vale a pena considerar.

A outra opção é adicioná-los como métodos não-estáticos no objeto de origem:

ou seja, mudando:.

public class BarUtil {
    public static Foo transform(Bar toFoo) { ... }
}

para

public class Bar {
    ...
    public Foo transform() { ...}
}

No entanto, em muitas situações, isso não é possível (por exemplo, a geração de código classe regular de XSD / WSDL / etc), ou ele vai fazer a classe muito tempo, e métodos de transformação muitas vezes pode ser uma verdadeira dor de objetos complexos e você só quero que eles em sua própria classe separada. Então, sim, eu tenho métodos estáticos em classes de utilitários.

A razão você será avisado longe de métodos estáticos é que usá-los perde uma das vantagens de objetos. Os objectos são destinados para encapsulamento de dados. Isto evita efeitos colaterais inesperados aconteça o que evita erros. Os métodos estáticos têm dados não encapsulado * e por isso não Garner este benefício.

Dito isto, se você não tem nenhum uso de dados internos, eles são bons para uso e um pouco mais rápido para executar. Certifique-se de dados globais não tocar neles embora.

  • Alguns idiomas também têm variáveis ??de nível de classe, o que permitiria para encapsulamento de dados e de métodos estáticos.

aulas estáticas são muito bem contanto que eles são usados ??nos lugares certos.

A saber: Métodos que são métodos 'folha' (eles não modificar o estado, eles simplesmente transformar a entrada de alguma forma). Bons exemplos disso são coisas como Path.Combine. Esses tipos de coisas são úteis e para fazer sintaxe terser.

problemas que tenho com a estática são numerosas:

Em primeiro lugar, se você tiver classes estáticas, dependências estão escondidos. Considere o seguinte:

public static class ResourceLoader
{
    public static void Init(string _rootPath) { ... etc. }
    public static void GetResource(string _resourceName)  { ... etc. }
    public static void Quit() { ... etc. }
}

public static class TextureManager
{
    private static Dictionary<string, Texture> m_textures;

    public static Init(IEnumerable<GraphicsFormat> _formats) 
    {
        m_textures = new Dictionary<string, Texture>();

        foreach(var graphicsFormat in _formats)
        {
              // do something to create loading classes for all 
              // supported formats or some other contrived example!
        }
    }

    public static Texture GetTexture(string _path) 
    {
        if(m_textures.ContainsKey(_path))
            return m_textures[_path];

        // How do we know that ResourceLoader is valid at this point?
        var texture = ResourceLoader.LoadResource(_path);
        m_textures.Add(_path, texture);
        return texture; 
    }

    public static Quit() { ... cleanup code }       
}

Olhando para TextureManager, você não pode dizer o que etapas de inicialização deve ser realizado por olhar para um construtor. É necessário aprofundar a classe para encontrar suas dependências e coisas inicializar na ordem correta. Neste caso, ele precisa do ResourceLoader para ser inicializado antes de executar. Agora ampliar este pesadelo dependência e você provavelmente pode adivinhar o que vai acontecer. Imagine tentar manter o código onde não há nenhuma ordem explícita de inicialização. Compare isso com a injeção de dependência com instâncias - nesse caso o código não vai mesmo compilação Se as dependências não são cumpridas

Além disso, se você usar estática que o estado de modificação, é como um castelo de cartas. Você nunca sabe quem tem acesso a quê, eo projeto tende a se parecer com um monstro de espaguete.

Finalmente, e tão importante, usando estática laços um programa para uma implementação específica. estática de código é a antítese do projeto para testabilidade. código de teste que está repleto de estática é um pesadelo. A chamada estática nunca pode ser trocado por um teste duplo (a menos que você usar estruturas de teste projetados especificamente para zombar de tipos estáticos), de modo que um sistema estático faz com que tudo o que usa-lo para ser um teste de integração instantânea.

Em suma, a estática são bons para algumas coisas e para pequenas ferramentas ou descartável código que eu não iria desencorajar o seu uso. No entanto, além disso, eles são um pesadelo sangrento para manutenção, um bom design e facilidade de teste.

Aqui está um bom artigo sobre os problemas: http://gamearchitect.net/2008/09/13/an-anatomy-of-despair-managers-and-contexts/

Essa parece ser uma abordagem razoável. A razão que você não quer usar muitas classes estáticas / métodos é que você acaba se afastando de programação orientada a objeto e mais para o reino da programação estruturada.

No seu caso, onde você está simplesmente transformando A para B, dizer que todos nós estamos fazendo está transformando texto para ir de

"hello" =>(transform)=> "<b>Hello!</b>"

Em seguida, um método estático faria sentido.

No entanto, se você está invocando estes métodos estáticos em um objeto com freqüência e ele tende a ser único para muitas chamadas (por exemplo, a maneira como você usá-lo depende da entrada), ou é parte do comportamento inerente do objeto , seria sábio para torná-lo parte do objeto e manter um estado dele. Uma maneira de fazer isso seria para implementá-lo como uma interface.

class Interface{
    method toHtml(){
        return transformed string (e.g. "<b>Hello!</b>")
    }

    method toConsole(){
        return transformed string (e.g. "printf Hello!")
    }
}


class Object implements Interface {
    mystring = "hello"

    //the implementations of the interface would yield the necessary 
    //functionality, and it is reusable across the board since it 
    //is an interface so... you can make it specific to the object

   method toHtml()
   method toConsole()
}

Edit: Um bom exemplo de grande uso de métodos estáticos são html helper métodos em Asp.Net MVC ou Ruby. Eles criam html elementos que não estão vinculados ao comportamento de um objeto, e são, portanto, estático.

Edit 2:. Programação funcional alterado para programação estruturada (por alguma razão eu fiquei confuso), adereços para Torsten para apontar isso

Recentemente reformulado um pedido para remover / modificar algumas classes que havia sido inicialmente implementados como classes estáticas. Com o tempo essas classes adquiridas tanto e as pessoas só manteve a marcação das novas funções como estático, já que nunca houve uma instância flutuando.

Assim, a minha resposta é que as classes estáticas não são inerentemente mau, mas pode ser mais fácil para começar a criar instâncias agora, então tem que refatorar mais tarde.

Eu costumava ir e voltar entre uma classe com um monte de métodos estáticos e um singleton. Ambos resolver o problema, mas o singleton pode ser muito mais facilmente substituídos por mais de um. (Programadores parecem sempre tão certo que haverá apenas 1 de algo e eu encontrei-me errado vezes o suficiente para abandonar completamente em métodos estáticos, exceto em alguns casos muito limitados).

De qualquer forma, o singleton dá-lhe a capacidade de depois passar algo para a fábrica para obter uma instância diferente e que altera o comportamento de todo o seu programa sem refatoração. Alterar uma classe mundial de métodos estáticos em algo com dados diferentes "Fazendo" ou um comportamento (classe infantil) ligeiramente diferente é uma grande dor na bunda.

E métodos estáticos não têm nenhuma vantagem similar.

Então, sim, eles são ruins.

Eu posso considerar um cheiro design. Se você está usando métodos principalmente estáticos, você provavelmente não tem um bom projeto OO. Não é necessariamente ruim, mas como com todos os cheiros que isso me faria parar e re-avaliar. Ele sugere que você pode ser capaz fazer um melhor design OO, ou que talvez você deve ir na outra direção e evitar OO inteiramente para este problema.

Enquanto não estado interno entra em jogo, isso é bom. Note-se que os métodos normalmente estáticas são esperados para ser thread-safe, então se você usar estruturas de dados auxiliares, usá-los de uma forma thread-safe.

Se você sabe que vai não necessidade de usar o estado interno do C, está tudo bem. Deve essa mudança sempre no futuro, porém, que você precisa para tornar o método não-estático. Se for non-static, para começar, você pode simplesmente ignorar o estado interno se você não precisa dele.

Se é um método de utilitário, é bom para torná-lo estático. Goiaba e Apache Commons são construídos sobre este princípio.

A minha opinião sobre isso é puramente pragmática. Se é o seu código de aplicativo, métodos estáticos geralmente não são a melhor coisa para ter. Os métodos estáticos têm sérias limitações de testes de unidade - eles não podem ser facilmente ridicularizado: você não pode injetar uma funcionalidade estática ridicularizado em algum outro teste. Você também não pode funcionalidade normalmente injetar em um método estático.

Assim, em minha lógica app que eu normalmente têm estática utilitário-como chamadas de métodos pequenos. Ou seja,

static cutNotNull(String s, int length){
  return s == null ? null : s.substring(0, length);
}

Uma das vantagens é que eu não testar tais métodos: -)

Bem, não há nenhuma bala de prata, é claro. classes estáticas são ok para pequenos utilitários / ajudantes. Mas o uso de métodos estáticos para a programação de lógica de negócios é certamente mal. Considere o seguinte código

   public class BusinessService
   {

        public Guid CreateItem(Item newItem, Guid userID, Guid ownerID)
        {
            var newItemId = itemsRepository.Create(createItem, userID, ownerID);
            **var searchItem = ItemsProcessor.SplitItem(newItem);**
            searchRepository.Add(searchItem);
            return newItemId;
        }
    }

Você vê uma chamada de método estático para ItemsProcessor.SplitItem(newItem); Cheira causa

  • Você não tem dependência explícita declarada e se você não cavar em código que você pode ignorar a ligação entre a sua classe e recipiente método estático
  • Você não pode testar BusinessService isolando-o de ItemsProcessor (a maioria das ferramentas de teste não classes estáticas simulados) e torna a unidade de teste impossível. Nenhuma unidade de testes == baixa qualidade

Os métodos estáticos são geralmente uma má escolha mesmo para código de apátrida. Em vez disso fazer uma única classe com estes métodos, instanciado uma vez e injetadas essas classes que querem usar os métodos. Tais classes são mais fáceis de simulação e teste. Eles são orientados muito mais objeto. Você pode envolvê-los com um proxy quando necessário. Estática fazer OO muito mais difícil e não vejo nenhuma razão para usá-los em quase todos os casos. Não 100%, mas quase todos.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top