Dal punto di vista dei principi SOLIDI la risposta di jgauffin ha senso. Tuttavia, non dovresti dimenticare i principi generali di progettazione, ad esempio nascondere le informazioni .
Vedo diversi problemi con l'approccio dato:
- Come hai sottolineato te stesso, le persone non si aspettano di utilizzare la parola chiave "nuova", quando l'oggetto creato non gestisce alcuno stato . Il tuo design riflette la sua intenzione. Le persone che usano la tua classe potrebbero essere confuse su quale stato gestisce e se le successive chiamate al metodo potrebbero comportare comportamenti diversi.
- Dal punto di vista della persona che usa la classe lo stato interiore è ben nascosto, ma quando si desidera apportare modifiche alla classe o semplicemente capirla, si stanno rendendo le cose più complesse. Ho già scritto molto sui problemi che vedo con i metodi di divisione solo per renderli più piccoli , specialmente quando si sposta lo stato nell'ambito della classe. Stai modificando il modo in cui la tua API dovrebbe essere utilizzata solo per avere funzioni più piccole! Questo secondo me lo sta decisamente portando troppo lontano.
Alcuni riferimenti correlati
Probabilmente un argomento principale sta nella misura in cui estendere il principio della responsabilità singola . "Se lo porti all'estremo e costruisci classi che hanno un motivo per esistere, potresti finire con un solo metodo per classe. Ciò causerebbe una grande espansione di classi anche per i processi più semplici, facendo sì che il sistema sia difficile da capire e difficile da cambiare ".
Un altro riferimento rilevante relativo a questo argomento: "Dividi i tuoi programmi in metodi che eseguono un compito identificabile. Mantieni tutte le operazioni in un metodo allo stesso livello di astrazione ". - Kent Beck Key qui è "lo stesso livello di astrazione". Ciò non significa "una cosa", poiché viene spesso interpretato. Questo livello di astrazione dipende interamente dal contesto per il quale si sta progettando.
Quindi qual è l'approccio corretto?
Senza conoscere il tuo caso d'uso concreto è difficile da dire. C'è uno scenario in cui a volte (non spesso) uso un approccio simile. Quando voglio elaborare un set di dati, senza voler rendere disponibile questa funzionalità per l'intero ambito di classe. Ho scritto un post sul blog a proposito di come Lambdas può migliorare ulteriormente l'incapsulamento . Ho anche iniziato una domanda sull'argomento qui su Programmers . Il seguente è un ultimo esempio di dove ho usato questa tecnica.
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 );
} );
Dato che il codice molto "locale" all'interno del codice ForEach
non viene riutilizzato da nessun'altra parte, posso semplicemente mantenerlo nella posizione esatta in cui è rilevante. Delineare il codice in modo tale che il codice che si basa l'uno sull'altro sia fortemente raggruppato insieme lo rende più leggibile secondo me.
Possibili alternative
- In C # potresti invece usare metodi di estensione. Operate quindi direttamente sull'argomento che passate a questo metodo "una cosa".
- Verifica se questa funzione in realtà non appartiene a un'altra classe.
- Renderlo una funzione statica in una classe statica . Questo è probabilmente l'approccio più appropriato, come si riflette anche nelle API generali a cui hai fatto riferimento.
bool arrayContainsSomestring = new List<string>(stringArray).Contains("somestring");
quando tutto ciò che mi interessava era quella particolare informazione e i metodi di estensione LINQ non sono disponibili. Funziona bene e si adatta all'interno di unaif()
condizione senza la necessità di saltare attraverso i cerchi. Certo, vuoi un linguaggio spazzatura se stai scrivendo un codice del genere.