Passei as últimas horas lendo sobre o uso das static
aulas 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 MVC
Web 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);
}
}
c#
object-oriented-design
asp.net-mvc
Matthew Verstraete
fonte
fonte
PrincipalContext
classe, e ser chamado como:PrincipalContext.Get(ouName)
. É essencialmente um método de fábrica.Respostas:
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!
fonte
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.
fonte
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.
fonte
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.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
,*Manager
e*Doer
as 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.
fonte
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.
fonte
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
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.
fonte