Statico (alternativa al modello di metodo template basato su classi per linguaggi orientati agli oggetti imperativi?

2

EDIT: nota che voglio un metodo di compilazione static , quando so esattamente cosa deve andare dove in fase di compilazione.

Spesso mi capita di avere più funzioni che seguono lo stesso schema, ma solo alcune parti cambiano. Spesso scelgo il Pattern Method Template, tuttavia approcci basati su classi (specialmente in c ++) sembrano molto ingombranti. Sono spesso costretto a creare oggetti reali quando davvero tutto ciò che sto cercando di fare è cambiare una riga per un'altra che non può essere anteposta o aggiunta alla routine che sto scrivendo, dove idealmente vorrei semplicemente generare un funzione data un pattern in fase di compilazione. Ho anche bisogno di creare classi private / protette dove la procedura abbia senso solo nella classe che sto usando. Tutto ciò sembra un enorme spreco.

Mi piacerebbe un approccio statico a questo, in cui so esattamente quale funzione mi piacerebbe utilizzare in ogni situazione, ma non voglio il codice duplicato tra ogni funzione in cui solo una piccola quantità cambia E 'possibile in qualcosa come C ++ senza ricorrere alla creazione di classi personalizzate per ogni caso questo accade? Ci sono "soluzioni" come la creazione di diverse funzioni personalizzate per ogni passaggio, ma senza TMP queste funzioni si accoppiano ad un alto livello e richiedono più parametri per essere passati intorno a quanto normalmente necessario, e non sembrano mai davvero liberarsi della duplicazione del codice .

MODIFICA l'esempio più recente che ho trovato da quando mi è stato chiesto degli esempi ...

class X{
    A m_class_member_1;
    B m_class_member_2;
    C m_class_member_3;
    D m_class_member_4;
    E m_class_member_5;
    ...
    void duplicateProcedure_1(){
        auto some_value = m_class_member_1.function();
        if(valuePassesTest(some_value)){
            auto some_other_value = m_class_member_2.function(some_value);
            m_class_member_3.function(some_other_value);
            m_class_member_4.function(some_other_value);
            // changed procedure
            m_class_member_5.function_1(some_other_value);
        }
    }

    void duplicateProcedure_2(){
        auto some_value = m_class_member_1.function();
        if(valuePassesTest(some_value)){
            auto some_other_value = m_class_member_2.function(some_value);
            m_class_member_3.function(some_other_value);
            m_class_member_4.function(some_other_value);
            //changed procedure
            m_class_member_5.function_2(some_other_value);
        }
    }
}

l'ultima riga in ciascuna è l'unica cosa che deve essere cambiata, tutto il resto deve essere uguale, ma dipendono anche dalle variabili create con la procedura, nonché dalle condizioni esterne all'ambito del loro blocco.

    
posta opa 09.06.2017 - 20:40
fonte

3 risposte

2

Hai ragione a essere cauto nell'abusare di astrazioni. Questo è ben descritto in questo articolo .

Posso vedere 3 alternative a questo:

  • Composizione: mantieni le 2 procedure duplicate ed estrai solo le parti comuni ad alcune funzioni private. Facile, leggibile, potrebbero esserci ancora alcune parti duplicate, ma è mantenuto ragionevole. Il lato negativo è che potresti venire a creare molte piccole funzioni private per questo.
  • Funzioni anonime / lambda; eccetto se hai buone ragioni per evitarlo (è per questo che parli di "imperativo" oo linguaggio?), risolve esattamente questo tipo di problema; ma potrebbe eventualmente portare a un codice meno leggibile.
  • E infine a volte ci concentriamo troppo sulla rimozione di parti duplicate, mentre non dovremmo. La duplicazione non è necessariamente negativa (come spiegato nel link sopra). Direi: prova a ridurre il codice duplicato fino a un certo punto. Componi finché è vantaggioso senza dubbio, ma non c'è motivo di vergognarsi quando si lascia un po 'di codice duplicato.
risposta data 09.06.2017 - 21:31
fonte
1

Non so se C ++ ti permette di passare metodi associati come callback, ma se lo fa, la soluzione più semplice è probabilmente qualcosa del tipo:

void consolidatedProcedure(SOME_CALLBACK_TYPE callback){
    auto some_value = m_class_member_1.function();
    if(valuePassesTest(some_value)){
        auto some_other_value = m_class_member_2.function(some_value);
        m_class_member_3.function(some_other_value);
        m_class_member_4.function(some_other_value);
        // changed procedure
        callback(some_other_value);
    }
}

void duplicateProcedure_1(){
    consolidatedProcedure(m_class_member_5.function_1);
}

void duplicateProcedure_2(){
    consolidatedProcedure(m_class_member_5.function_2);
}

Dici che stai cercando una soluzione generale per questi tipi di situazioni. Il problema è, più la domanda è generale, più la risposta è generale. La soluzione generale consiste nel passare oggetti e / o funzioni come parametri o utilizzare modelli. Se desideri una risposta più specifica, probabilmente avrai bisogno di una domanda più specifica.

    
risposta data 09.06.2017 - 21:29
fonte
1

Sarai in grado di evitare la duplicazione del codice utilizzando una funzione comune che accetta una funzione lambda come argomento.

void duplicateProcedure_1(){
   commonProcedure([&m_class_member_5](some_other_value_type some_other_value)
                   {m_class_member_5.function_1(some_other_value);});
    }
}

void duplicateProcedure_2(){
   commonProcedure([&m_class_member_5](some_other_value_type some_other_value)
                   {m_class_member_5.function_2(some_other_value);});
    }
}

private:

template <typename F>
void commonProcedure(F f){
    auto some_value = m_class_member_1.function();
    if(valuePassesTest(some_value)){
        auto some_other_value = m_class_member_2.function(some_value);
        m_class_member_3.function(some_other_value);
        m_class_member_4.function(some_other_value);
        f(some_other_value);
    }
}

Tuttavia, capisco che questo è un codice illustrativo, non necessariamente il codice di produzione. Se il codice di produzione è più coinvolto, è molto probabile che perderà la leggibilità. Il costo della leggibilità persa potrebbe essere superiore al costo delle linee di codice duplicate.

Se commonProcedure sarà usato da 5 o più procedure, vorrei andare con la soluzione di cui sopra.

Se commonProcedure sarà usato da 3 o meno procedure, andrei con il codice duplicato.

Se commonProcedure sarà utilizzato da esattamente 4 procedure, hai pesato il costo e i benefici degli approcci per la tua situazione e fai un giudizio.

    
risposta data 09.06.2017 - 21:56
fonte

Leggi altre domande sui tag