Devo usar classes estáticas para métodos que executam tarefas comuns e seriam chamados através do meu aplicativo?

8

Passei as últimas horas lendo sobre o uso das staticaulas e tentando descobrir se eu deveria usá-las ou não, mas ainda não cheguei a nenhum tipo de conclusão. Parece que o argumento poderia ser de qualquer maneira. No meu aplicativo, criei o que chamo de "classes auxiliares", que contém métodos que farão tarefas muito comuns para mim e seriam chamados através do meu aplicativo (uso do ASP.Net MVCWeb App C#) e a pergunta simples é: eles realmente devem ser estáticos ou não? ?

Aqui está um exemplo de um dos meus ajudantes.

public static class ActiveDirectoryHelper
{
    public static PrincipalContext GetPrincipalContext(string ouName)
    {
        var fullOUName = string.Concat("OU=", ouName,",DC=");

        return new PrincipalContext(ContextType.Domain, "", fullOUName, ConfigurationManager.AppSettings["ServiceAccountUser"], ConfigurationManager.AppSettings["ServiceAccountPassword"]);
    }

    public static PrincipalSearcher GetAllUsersInOU(string ouName)
    {
        var principalContext = GetPrincipalContext(ouName);
        var userPrincipal = new UserPrincipal(principalContext);
        return new PrincipalSearcher(userPrincipal);
    }

    public static UserPrincipal GetUserPrincipal(string userName, string ouName)
    {
        var principalContext = GetPrincipalContext(ouName);
        return UserPrincipal.FindByIdentity(principalContext, userName);
    }
}
Matthew Verstraete
fonte
Não há mandato para evitar classes estáticas. Use-os quando for útil. Há boas razões para os designers de idiomas incluí-los.
Robert Harvey
5
Por que você não incluiu esses métodos como métodos estáticos em suas classes associadas, em vez de colocá-los todos em uma classe auxiliar? Por exemplo, o primeiro método pode ser um método estático na PrincipalContextclasse, e ser chamado como: PrincipalContext.Get(ouName). É essencialmente um método de fábrica.
Robert Harvey
@RobertHarvey Acho que não estou seguindo. Essa classe está na minha BLL e é chamada de muitas outras classes (controladores) na WebUI, bem como em um aplicativo de console C # que faz manutenção noturna e para evitar ter que recodificá-la o tempo todo, acabei de escrevê-la em uma classe auxiliar.
Matthew Verstraete
5
O desenvolvimento de software é sempre uma série de compensações. Qual técnica você escolhe usar depende de qual conjunto de trocas você deseja aplicar.
Robert Harvey
4
@RobertHarvey: PrincipalContext e UserPrincipal são classes de biblioteca,
kevin Cline

Respostas:

3

Eu acho que classes estáticas são boas em muitos casos. Eu poderia dizer "use-os quando for útil", mas isso não ajuda muito.

Minha regra geral é (como sempre): Estou ocultando alguma dependência? Se você acha que uma "classe auxiliar" é útil (embora tenha cuidado com a baixa coesão), por todos os meios, vá em frente. Apenas verifique se seus métodos não acessam o estado global. Métodos estáticos puros são adoráveis. Os métodos estáticos que dependem de alguns globais ou que abrem conexões com o banco de dados ou que leem do disco / algum arquivo de configuração são bombas-relógio.

Eles tornam o teste do aplicativo muito difícil (a única maneira de fazer isso é executar manualmente todo o sistema ou, com testes automáticos frágeis do sistema completo, você não terá granularidade). Eles também tornam impossível trocar implementações.

Apenas lembre-se do princípio de inversão de dependência e do princípio de aberto / fechado! Verifique se suas aulas são conectáveis. Certifique-se de que eles não puxem coisas do nada. Se você fizer isso, vá em frente e faça quantos métodos estáticos desejar!

sara
fonte
2

Parece que você está ocultando uma dependência externa ao Active Directory usando esta classe estática. Um problema aqui é que, se você estiver tentando testar a classe que chama esses métodos, não poderá falsificar chamadas estáticas. Então você imediatamente inibe a testabilidade do seu código. Eu refatoraria isso para uma interface, algo como IProvideActiveDirectoryInformation e a classe concreta, ActiveDirectoryInformationProvider. Em seguida, passe a interface no construtor do seu controlador. Isso permitirá que você conecte a classe de concreto com um recipiente DI. Também permitirá que você falsifique o ActiveDirectoryInformationProvider e retorne o que quiser para os métodos de interface.

Eu também consideraria não repassar coisas como o objeto PrincipalSearcher na interface. Se seu método for GetAllUsersInOU (), eu esperaria uma lista de usuários ou nomes de usuários.

Fran
fonte
Não sabe ao certo o que você quer dizer com "ocultando uma dependência externa ao Active Directory". Faço leituras do AD e essa classe foi criada para reduzir a codificação necessária para fazer conexões e obter dados básicos.
Matthew Verstraete
é o que eu quero dizer. veja a resposta de Kai para uma explicação mais completa. Mas o que você faz é não tornar seu código dependente de todas as dependências do código que você está chamando.
Fran
1

Uma classe deve ser estática se existir apenas como um conceito abstrato em seu aplicativo.

Por exemplo, digamos que você esteja criando um clone do Twitter. Você pode ter dois tipos de tweets, tweets de usuários e anúncios. Ambos compartilham comportamentos comuns, mas são diferentes. Portanto, você deseja usar o polimorfismo e uma fábrica para criar um ou outro.

Essas duas classes de tweets devem ser concretas, pois são entidades reais. Seu domínio é definido por essas classes.

A fábrica deve ser estática, porque existe apenas em um nível abstrato para tornar seu aplicativo melhor projetado e para ajudá-lo a reutilizar o código que criará um tipo de tweet. Seu domínio não está definido em nenhum nível por esta fábrica.

Portanto, se você acha que uma classe nunca deve ser instanciada, mas não precisa ser estendida para ser usada, é provavelmente um bom sinal de que deve ser estática.

Steve Chamaillard
fonte
Isso realmente dependeria do tipo de fábrica. Uma simples static A BuildA() { return new A(); }certeza, tudo bem. mas se você precisar de algo mais complexo, como quando A tem dependências que precisam ser injetadas ou quando partes diferentes do seu sistema precisam de instâncias de fábrica diferentes (padrão abstrato de fábrica), um método estático não é suficiente.
Sara
Obrigado por seu comentário. Não parece que a fábrica da qual você está falando seja muito abstrata no final, parece que é um conceito concreto que precisa ser instanciado (especialmente porque você disse que precisava de várias fábricas diferentes). Então, novamente, nada está definido de qualquer maneira e apenas conselhos podem ser dados sobre esse assunto.
21416 Steve Steveillillard
1
Existem muitas entidades que são "Pure Fabrication", que não são de forma alguma convertidas para o domínio, por exemplo, UserDao. Isso não indica se deve ou não ser estático. Deve ser estático se as unidades de trabalho que ele faz, não dependem umas das outras e devem ser extensíveis, por exemplo, classe Math.
21416 Chris Wohlert #
@ChrisWohlert comentário muito interessante, mas isso não depende apenas do contexto? Eu sinto que um aplicativo sobre matemática gostaria que uma aula de matemática fosse uma das principais e instanciada. O UserDao é algum tipo de repositório entre a camada Usuário e DB? Se sim, por que você iria querer instanciar? Você ainda pode injetá-lo, mesmo que nunca crie um objeto para isso, já que ele não "existe", o que você acha?
9788 Steve Rogers #
1
@SteveChamaillard Você supõe que faz sentido instanciar apenas objetos "reais". Isso me lembra essas analogias da OOP 101, nas quais você tem a classe abstrata "Fruit" e a "Apple" herdada - onde os objetos OOP representam objetos do mundo real. Mas não há necessidade de se limitar assim. OOP é uma ferramenta, para que as pessoas usam objetos para "fabricações puras", mesmo que faz a sua vida mais fácil e não vejo nada de errado com ele ...
QbD
1

Uma das coisas sugeridas em Programação Orientada a Objetos é Bad (o título é para obter a sua atenção, e o conteúdo é disputada mas divertido) é que *Handler, *Managere *Doeras classes em geral são um cheiro de código que indicam alguém tentando orientação a objetos vigor em um problema mais adequado para uma implementação processual.

Em C #, você pode usar classes estáticas como espaços de nomes de módulo para procedimentos e, de preferência, nomeá-las como tal. Acho que é assim que se faz, mas não no seu caso particular.

Os aplicativos de sua implementação específica terão dependências comportamentais do estado global (digamos, as permissões de um usuário em particular) e, como tal, devem ser uma dependência injetada para que o código que a usa possa ser testado separadamente.

Robert Jørgensgaard Engdahl
fonte
0

Eu posso estar perdendo alguma coisa, mas, na minha opinião, a resposta se resume aos métodos e variáveis ​​de membro.

Se tudo isso for estático, a própria classe pode (e deve ser) tornar-se estática. Caso contrário, não é uma classe estática.

Nota: não há nada que force a classe a ser estática, mesmo que os métodos e variáveis ​​sejam todos estáticos.

Robbie Dee
fonte
A mesma classe que faz as mesmas coisas pode ser projetada para ser estática e não estática. Sempre há uma escolha de design a ser feita.
Sara
Pode haver uma opção de design, mas a implementação é um tanto arbitrária. Forças nada que você rotular o método ou classe estática - mesmo com a falta de uma variável de instância embora algumas ferramentas como ReSharper que pegar isso ...
Robbie Dee
Mas quando devo tornar todos os métodos / membros estáticos ou não? Essa é a questão. Quando usar estática e quando não usar.
Matthew Verstraete
Se nenhuma das variáveis ​​ou métodos membros depender de uma instância da classe - você terá uma classe estática de boa-fé. Por sua natureza, essas tendem a ser coisas como classes auxiliares ou utilitários e similares.
Robbie Dee
0

Considere a linguagem de programação que você está usando (C #) como um conjunto de ferramentas.

Não existe um livro de regras, não "deveria" ou "não deveria".

Veja o trabalho que está fazendo e escolha a melhor ferramenta para o trabalho.

Se você precisar de uma coleção de métodos globalmente disponível, a mesma para todos os threads, as classes estáticas são uma boa ferramenta. Se você deseja armazenar dados dentro da classe (diferente para cada thread), eles provavelmente não são.


fonte
0

Não há nada errado na sua aula de auxiliar. Eu tenho que confessar que uso esse tipo de Utils , Helpers ou Holders para tornar acessíveis certos recursos / lógicas de lugares diferentes.

No entanto, um arquiteto da minha empresa me diz repetidamente que essas classes geralmente reúnem códigos nos quais eu não sei onde colocar. Ele também não gosta, porque você pode trazer componentes de camadas nas quais as camadas superior / inferior não devem ter acesso e elas executam tarefas com suas responsabilidades. Também traz alguns problemas no momento do teste.

Eu não me importo. Eu os uso e os uso tão adequadamente quanto acho que deve ser usado. E isso funciona bem. Então não se preocupe.

É verdade que, no momento do teste de unidade, você terá dificuldade em zombar dele. Mas vai demorar um pouco mais para fazê-lo. Existem bibliotecas que passam por esse problema.

Outra abordagem pode impedir você desse tipo de falha (no teste). Por exemplo, padrão Singleton. Injetando a instância como dependência de componente e transformando métodos em métodos de instância.

De qualquer forma, até agora, vejo que suas soluções me parecem boas.

Laiv
fonte