Ripetizione del codice rispetto al metodo multi responsabile

11

Cerco di seguire il Single Responsibility Principle (SRP) e anche di omettere le ripetizioni di codice. Tuttavia ci sono spesso luoghi in cui ci sono ripetizioni di codice che non sono altro che blocchi di codice di invocazioni che sono resistenti all'estrazione di essi in almeno un metodo con nome significativo:

DoAction1();
DoAction2();

if (value)
    DoAction3();

DoAction4();

Qual è il modo migliore per estrarre tale codice in un metodo e come chiamarlo?

    
posta yBee 22.11.2013 - 09:35
fonte

5 risposte

13

Penso che sia solo una questione di nominare correttamente il metodo estratto. Temo che non esista una soluzione universale e dovrai farlo caso per caso. Se stai ripetendo questo stesso pezzo di codice in più di 1 posto, è inevitabile che ci sia un significato per le tue azioni e hai bisogno di guardare attentamente (può essere discusso) per trovare quel significato e dargli un nome.

Se c'è qualche consolazione, il vincitore di Spring per i nomi di classi lunghe è AbstractInterruptibleBatchPreparedStatementSetter che ha 49 caratteri.

    
risposta data 22.11.2013 - 15:12
fonte
11

In realtà stai soffrendo del compito più difficile da fare da parte di un programmatore - Nomi di parole . Scusa per una risposta così matura, ma non ho potuto resistere. Puoi trovare molte persone ne soffrono , anche su internet puoi trova questo tipo di saggio .

Ora se il tuo codice ripetitivo è tutto insieme ne risulta un lavoro e quei metodi non vengono utilizzati da altri metodi, sono semplicemente Metodo helper e quindi il metodo risultante può essere chiamato doXXX o makeXXX ... Penso che tu abbia capito il punto.

Come Chandranshu ha detto "Se stai ripetendo questo [...] significato e dandolo un nome. " è al punto e appropriato.

Cortesiadelsito: Pagina Facebook CodeChef Foto

    
risposta data 22.11.2013 - 16:37
fonte
2

Penso che tu stia prendendo il principio della ripetizione del codice troppo lontano. Pensa al punto di evitare la ripetizione del codice. Il punto è ridurre la quantità di codice che deve essere controllato quando c'è un cambiamento nella logica e aumentare la comprensione mediante il factoring di blocchi chiaramente intesi allo scopo.

Le cadute del factoring per evitare la ripetizione sono che se uno dei blocchi condivisi deve cambiare, ora hai bisogno di un'eredità ancora più complessa o di un passaggio tra implementazione standard e non standard.

Quindi valuta attentamente la possibilità che la logica per anche una di questi blocchi cambi senza gli altri contro i benefici di comprensione acquisiti mettendo a fattor comune questa comunanza. Se un'implementazione potrebbe dividersi dagli altri, è meglio che stiate semplicemente ripetendo il codice.

Pur mantenendo questo codice ripetuto, man mano che diventa più complesso e il dominio del problema diventa più definito, puoi quindi trovare più appropriato il fattore delle sezioni ripetute, ora più complesse, ma anche più definite fuori.

Di solito cerco di mantenere la stessa identità di editor di testo per un po 'finché non riesco a vedere se qualcosa che sembra ripetitivo si riveli meritevole di factoring. Continuo la ripetizione, ma tengo d'occhio il futuro di quel blocco mantenendolo più facilmente testuale in seguito.

La maggior parte del tempo, la stessa cosa, e il possibile factoring, cominciano a dissiparsi, come regole di business reali, capricciose e logiche altamente dipendenti, spesso arbitrarie; si aggiungono come affrontare le stranezze di diverse implementazioni di database comuni (ANSI_NULLS o alcune di queste); forzare quella che sembrava una pura logica in un pasticcio contorto, cercando di fornire una logica decisionale ragionevole e giustificabile di fronte al caos dello stato del settore.

Mi sembra che se le persone cercassero di calcolare ciò che stai cercando di calcolare, avremmo un'intera libreria di costrutti senza valore come Do1Then2If2False Do1IfTrueDo2.

Deve essere più complesso e più chiaro che il blocco non cambierà per giustificare il factoring.

È software . Puoi tornare indietro e modificare un paio di blocchi uguali in questo momento. Ci vorranno 5 minuti. E puoi risparmiare ore di factoring sprecato, e quindi ore in più di sprecato ereditarietà e cambio di sviluppo, lasciandolo e assicurandoti di avere una buona tastiera anti-RSI.

    
risposta data 24.11.2013 - 03:16
fonte
1

Se segui veramente il principio di responsabilità singola, allora questo blocco di codice deve avere uno scopo specifico, giusto? Altrimenti questi metodi sarebbero in classi separate.

Quindi, qual è lo scopo di questo blocco di codice? Determina e dovresti riuscire a trovare un nome.

Se ancora non riesci a capire il nome di questa cosa, forse questi metodi in realtà non appartengono affatto. Cioè questo codice / codice ha più di una responsabilità. In tal caso, il refactoring per suddividere le attività potrebbe rivelare un nome migliore per l'uso.

    
risposta data 23.11.2013 - 05:12
fonte
1

Ho avuto una situazione che potrebbe essere simile alla tua:

Esiste una classe che definisce la funzionalità dell'oggetto che rappresenta:

class Functionality
{
protected:
void functionA();
void functionB();
...
void functionZ();
}

Poi c'è una classe che definisce i flussi di lavoro per le operazioni di alto livello eseguite dall'oggetto:

class Workflows: private Functionality
{
    void WorkflowA()
    {
        functionA();

        if (m_bValue) {
            functionB();
        }

        functionC();
    }
    ...
    void WorkflowB();
}

Se ti trovi in una situazione simile, identifica cosa le tue classi rappresentano (in questo caso funzionalità / flussi di lavoro) e quindi dai un nome ai metodi di conseguenza.

Dichiarazione di non responsabilità: i nomi di classe utilizzati in questo esempio sono grossolanamente imprecisi, ma i nomi dei metodi forniscono un indizio. Discrezione consigliata.

    
risposta data 23.11.2013 - 08:37
fonte