Dettagli di ottimizzazione fine in funzione C ++ per diversi clienti

2

La società per cui lavoro segue un modello aziendale in cui esiste un prodotto principale (originariamente scritto in C, ora in C ++) con alcune implementazioni predefinite, ma i dettagli sono fatti su misura per ciascun cliente (ci sono circa 10-20 di essi ). Qual è il miglior approccio di programmazione in uno scenario del genere? Esiste un buon modello di progettazione / metodologia / paradigma / qualunque cosa là fuori che renda il riuso del codice e la manutenzione ottimale? (Il controllo delle versioni è tanto un mal di testa, forse sarà un'altra domanda SO più avanti).

Esempio: il sistema fornisce un servizio implementato come una funzione:

int doServiceA(const string & params);

Una routine di dispatcher comune chiama questa funzione:

void dispatch(const string & cmd, const string & params)
{
    int ret = 0;
    if (cmd == "serviceA") {
        ret = doServiceA(params);
    }
    //...
}

Nel nostro primo approccio l'implementazione di doServiceA era piena di # ifdef per gestire i requisiti unici dei clienti.

Dopo un paio di anni passammo all'utilizzo delle funzioni virtuali:

Modulo principale:

class ServiceA
{
    virtual int execute(const string & params); // with default implementation
};

ServiceA & getServiceA(); // factory method declaration

void dispatch(const string & cmd, const string & params)
{
    int ret = 0;
    if (cmd == "serviceA") {
        ret = getServiceA().execute(params);
    }
    //...
}

Estensione per cliente XXX:

class XXXServiceA : public ServiceA
{
    virtual int execute(const string & params); // implementation containing XXX-specific parts
};

ServiceA & getServiceA() // factory method implementation
{
    static XXXServiceA s;
    return s;
}

Estensione per il cliente YYY:

class YYYServiceA : public ServiceA
{
    virtual int execute(const string & params); // implementation containing YYY-specific parts
};

ServiceA & getServiceA() // factory method implementation
{
    static YYYServiceA s;
    return s;
}

Finora siamo stati d'accordo con questa tecnica, ma ho alcune preoccupazioni:

  1. In che modo differisco dall'implementazione predefinita quando un cliente richiede un piccolo cambiamento nel mezzo del mio servizio? Suppongo che dovrei suddividere ServiceA :: execute () in pezzi il più piccolo possibile e renderli tutti virtuali (dato che non posso davvero prevedere quali parti saranno personalizzate in seguito)?

  2. La creazione di un oggetto senza stato ti sembra di violare il concetto di OOP per ragioni tecniche.

  3. A volte una modifica ha senso per più clienti che si traduce nella duplicazione del codice (XXXServiceA e YYYServiceA con le stesse implementazioni parziali) o nelle gerarchie di ereditarietà complesse (quando si aggiunge una classe tra ServiceA e i suoi discendenti per ospitare il codice comune).

  4. Solo la sensazione che i virtual potrebbero non essere lo strumento giusto in quanto è un mezzo per ottenere il polimorfismo di runtime mentre quello di cui ho bisogno è il polimorfismo in fase di compilazione (non esistono oggetti XXXServiceA e YYYServiceA nello stesso binario). / p>

Ho sperimentato molte cose di cui ho letto (policy, mixin, CRTP) ma fino ad ora non sono riuscito a migliorare molto sul progetto di cui sopra. Mi chiedo se mi manca qualcosa di veramente semplice qui?

    
posta peti 10.05.2016 - 16:56
fonte

1 risposta

0

1.Tiny changes

Non c'è magia disponibile per questo aspetto:

  • o è possibile definire l'esecuzione come un insieme di funzioni virtuali più primitive che è possibile sovrascrivere per scopi di personalizzazione;
  • oppure puoi utilizzare un design basato su criteri usando per ottenere lo stesso effetto, ma al momento della compilazione (ma con problemi strutturali simili come sopra)
  • oppure potresti considerare attiva / disattiva
  • oppure devi duplicare e mantenere il codice ridondante.

2.Stateless objects

Questa è una domanda dogmatica che non ti porterà più vicino a nessuna soluzione. Posso assicurarti che i tuoi sentimenti negativi non influenzeranno la precisione del tuo codice.

3.Comune modifiche per più clienti

La condivisione di parti di codice comuni per più clienti è qualcosa che è un buon candidato per il refactoring del codice con un modello di progettazione basato su modelli.

4.runtime vs. compile-time

Dal momento che i tuoi problemi sembrano riguardare le variazioni specifiche del cliente e tu compili il codice per i clienti, l'approccio in fase di compilazione sembra in effetti essere più adeguato. Utilizza i modelli: le classi specifiche del client diventerebbero un argomento modello.

template <class SerA> 
ServiceA & getServiceA() // factory method implementation
{
    static SerA s;
    return s;
}   

Per la creazione degli oggetti potresti usare molto bene una base di fabbrica astratta sui modelli , in fase di compilazione.

    
risposta data 12.05.2016 - 23:56
fonte

Leggi altre domande sui tag