Recentemente, eu estava revisando algumas classes estáticas da "bolsa de utilidade" do estilo Helper flutuando em torno de algumas grandes bases de código C # com as quais trabalho, basicamente como o seguinte trecho muito condensado:
// Helpers.cs
public static class Helpers
{
public static void DoSomething() {}
public static void DoSomethingElse() {}
}
Os métodos específicos que revi são
- principalmente não relacionados entre si,
- sem estado explícito persistido através de invocações,
- pequeno e
- cada um consumido por uma variedade de tipos não relacionados.
Edit: O item acima não pretende ser uma lista de supostos problemas. É uma lista de características comuns dos métodos específicos que estou revisando. É um contexto para ajudar as respostas a fornecer soluções mais relevantes.
Apenas para esta pergunta, vou me referir a esse tipo de método como um GLUM (método geral de utilitário leve). A conotação negativa de "triste" é parcialmente pretendida. Me desculpe se isso parece um trocadilho idiota.
Mesmo deixando de lado meu ceticismo padrão sobre GLUMs, não gosto das seguintes coisas sobre isso:
- Uma classe estática está sendo usada apenas como um espaço para nome.
- O identificador de classe estática é basicamente sem sentido.
- Quando uma nova GLUM é adicionada, (a) essa classe "bolsa" é tocada sem um bom motivo ou (b) uma nova classe "bolsa" é criada (o que por si só não costuma ser um problema; o ruim é que a nova classes estáticas frequentemente repetem o problema de falta de relação, mas com menos métodos).
- A meta-nomeação é inevitavelmente horrível, não-padrão e, normalmente, internamente inconsistentes, se é
Helpers
,Utilities
ou o que quer.
Qual é um padrão razoavelmente bom e simples para refatorar isso, de preferência abordando as preocupações acima e de preferência com o mínimo de toque possível?
Eu provavelmente deveria enfatizar: todos os métodos com os quais estou lidando não são pareados entre si. Não parece haver uma maneira razoável de decompô-los em sacos de métodos estáticos de granulação mais fina e ainda com vários membros.
fonte
Respostas:
Eu acho que você tem dois problemas intimamente relacionados entre si.
Esses problemas podem ser corrigidos combinando apenas métodos logicamente relacionados em uma classe estática e movendo os outros para sua própria classe estática. Com base no domínio do problema, você e sua equipe devem decidir quais critérios serão usados para separar métodos em classes estáticas relacionadas.
Preocupações e possíveis soluções
Os métodos não têm relação entre si - problema. Combine métodos relacionados em uma classe estática e mova métodos não relacionados para suas próprias classes estáticas.
Os métodos sem estado explícito persistiram nas invocações - não é um problema. Métodos sem estado são um recurso, não um bug. O estado estático é difícil de testar de qualquer maneira e só deve ser usado se você precisar manter o estado através de invocações de método, mas existem maneiras melhores de fazer isso, como máquinas de estado e a
yield
palavra - chave.Os métodos são pequenos - não é um problema. - Os métodos devem ser pequenos.
Cada método é consumido por uma variedade de tipos não relacionados - não é um problema. Você criou um método geral que pode ser reutilizado em muitos lugares não relacionados.
Uma classe estática está sendo usada apenas como um espaço para nome - não é um problema. É assim que métodos estáticos são usados. Se esse estilo de chamar métodos o incomodar, tente usar métodos de extensão ou a
using static
declaração.O identificador de classe estática é basicamente sem sentido - problema . Não faz sentido porque os desenvolvedores estão colocando métodos não relacionados nele. Coloque métodos não relacionados em suas próprias classes estáticas e forneça nomes específicos e compreensíveis.
Quando um novo GLUM é adicionado, (a) essa classe "bag" é tocada (tristeza do SRP) - não é um problema se você seguir a ideia de que apenas métodos relacionados à lógica devem estar em uma classe estática.
SRP
não é violado aqui, porque o princípio deve ser aplicado a classes ou métodos. A responsabilidade única das classes estáticas significa conter métodos diferentes para uma "idéia" geral. Essa ideia pode ser um recurso ou uma conversão, ou iterações (LINQ), normalização ou validação de dados ...ou com menos frequência (b) uma nova classe "bolsa" é criada (mais bolsas) - não é um problema. Classes / classes / funções estáticas - são as nossas ferramentas (desenvolvedores), que usamos para projetar software. Sua equipe tem alguns limites para o uso de aulas? Quais são os limites máximos para "mais malas"? A programação tem tudo a ver com contexto, se, para uma solução em seu contexto específico, você terminar com 200 classes estáticas, que são compreensivelmente nomeadas, logicamente colocadas em namespaces / pastas com hierarquia lógica - não é um problema.
A meta-nomeação é inevitavelmente horrível, não-padrão e, normalmente, internamente inconsistentes, se é Helpers, Utilities, ou qualquer outra coisa - problema. Forneça nomes melhores que descrevam o comportamento esperado. Mantenha apenas métodos relacionados em uma classe, que fornecem ajuda para uma melhor nomeação.
fonte
A
com 100 classes estáticas de método único (em 100 arquivos) do que uma classe estáticaA
com 100 métodos em um único arquivo.Math
classe estática.Apenas adote a convenção de que classes estáticas são usadas como espaços para nome em situações como essa em C #. Os espaços para nome recebem bons nomes, assim como essas classes. O
using static
recurso do C # 6 também facilita a vida.Nomes de classe malcheirosos
Helpers
indicam que os métodos devem ser divididos em classes estáticas melhor nomeadas, se possível, mas uma de suas suposições enfatizadas é que os métodos com os quais você está lidando são "não relacionados aos pares", o que implica dividir para uma nova classe estática por método existente. Provavelmente tudo bem, seComo um exemplo artificial,
Helpers.LoadImage
pode se tornar algo parecidoFileSystemInteractions.LoadImage
.Ainda assim, você pode acabar com sacos de método de classe estática. Algumas maneiras de isso acontecer:
É importante lembrar que esses pacotes de métodos de classe estática não são muito incomuns em bases de código C # reais. Provavelmente não é patológico ter alguns pequenos .
Se você realmente vê uma vantagem em ter cada método semelhante à "função livre" em seu próprio arquivo (o que é bom e vale a pena se você honestamente julgar que ele realmente beneficia a capacidade de manutenção do seu projeto), considere transformar essa classe estática em vez de estática classe parcial, empregando o nome da classe estática semelhante a como você usaria um espaço para nome e consumindo-o via
using static
. Por exemplo:Program.cs
Foo / Bar.cs
Foo / Baz.cs
Flob / Wibble.cs
Flob / Wobble.cs
fonte
Geralmente você não deve ter ou exigir nenhum "método geral de utilidade". Na sua lógica de negócios. Dê outra olhada e coloque-os em um local adequado.
Se você está escrevendo uma biblioteca de matemática ou algo assim, eu sugeriria, embora eu normalmente os odeie, Métodos de Extensão.
Você pode usar os Métodos de extensão para adicionar funções aos tipos de dados padrão.
Por exemplo, digamos que eu tenho uma função geral MySort () em vez de Helpers.MySort ou adicionando um novo ListOfMyThings.MySort Eu posso adicioná-lo a IEnumerable
fonte