De uma perspectiva dos princípios do SOLID , a resposta de jgauffin faz sentido. No entanto, você não deve esquecer os princípios gerais de design, por exemplo, ocultação de informações .
Vejo vários problemas com a abordagem fornecida:
- Como você mesmo apontou, as pessoas não esperam usar a palavra-chave 'new', quando o objeto criado não gerencia nenhum estado . Seu design reflete sua intenção. As pessoas que usam sua classe podem ficar confusas quanto ao estado que gerencia e se as chamadas subseqüentes ao método podem resultar em comportamento diferente.
- Da perspectiva da pessoa que usa a classe, o estado interno está bem oculto, mas, ao querer fazer modificações na classe ou simplesmente entendê-la, você está tornando as coisas mais complexas. Eu já escrevi muito sobre os problemas que vejo nos métodos de divisão apenas para torná-los menores , especialmente ao mover o estado para o escopo da classe. Você está modificando a maneira como sua API deve ser usada apenas para ter funções menores! Na minha opinião, isso definitivamente está levando longe demais.
Algumas referências relacionadas
Possivelmente, um ponto principal de argumentação está em como esticar o Princípio da Responsabilidade Única . "Se você levar isso ao extremo e criar classes que tenham um motivo para existir, poderá acabar com apenas um método por classe. Isso causaria uma grande expansão de classes até nos processos mais simples, fazendo com que o sistema fosse difícil de entender e difícil de mudar ".
Outra referência relevante relacionada a este tópico: "Divida seus programas em métodos que executam uma tarefa identificável. Mantenha todas as operações em um método no mesmo nível de abstração ". - Kent Beck Key aqui é "o mesmo nível de abstração". Isso não significa "uma coisa", como muitas vezes é interpretado. Esse nível de abstração é totalmente de acordo com o contexto para o qual você está projetando.
Então, qual é a abordagem adequada?
Sem conhecer seu caso de uso concreto, é difícil dizer. Há um cenário em que às vezes (não frequentemente) uso uma abordagem semelhante. Quando quero processar um conjunto de dados, sem querer disponibilizar essa funcionalidade para todo o escopo da classe. Eu escrevi um post sobre isso, como lambdas podem melhorar ainda mais o encapsulamento . Eu também comecei a uma pergunta sobre o tema aqui na programadores . A seguir, é apresentado um exemplo mais recente de onde eu usei essa técnica.
new TupleList<Key, int>
{
{ Key.NumPad1, 1 },
...
{ Key.NumPad3, 16 },
{ Key.NumPad4, 17 },
}
.ForEach( t =>
{
var trigger = new IC.Trigger.EventTrigger(
new KeyInputCondition( t.Item1, KeyInputCondition.KeyState.Down ) );
trigger.ConditionsMet += () => AddMarker( t.Item2 );
_inputController.AddTrigger( trigger );
} );
Como o código muito 'local' dentro do código ForEach
não é reutilizado em nenhum outro lugar, posso simplesmente mantê-lo no local exato em que é relevante. Esboçar o código de tal maneira que o código que depende um do outro seja fortemente agrupado o torna mais legível na minha opinião.
Alternativas possíveis
- Em C #, você pode usar métodos de extensão. Portanto, opere o argumento diretamente que você passa para esse método de "uma coisa".
- Veja se essa função realmente não pertence a outra classe.
- Torne uma função estática em uma classe estática . Essa provavelmente é a abordagem mais apropriada, como também é refletida nas APIs gerais às quais você se referiu.
bool arrayContainsSomestring = new List<string>(stringArray).Contains("somestring");
quando tudo o que importava era aquela informação específica e os métodos de extensão LINQ não estão disponíveis. Funciona bem e se encaixa dentro de umaif()
condição sem precisar saltar através de aros. Obviamente, você quer um idioma coletado de lixo se estiver escrevendo um código assim.