Scegliere un tipo concreto in base a un parametro di configurazione

1

Ho una base di codice che contiene diverse istanze dello schema seguente, il cui punto chiave è che il tipo concreto della classe viene deciso in fase di esecuzione in base a una stringa da un file di configurazione.

class Foo {
public:
    virtual void bar() = 0;
};

class AFoo : Foo {
public:
    void bar() {
        // ...
    }

    static Foo* create() {
        return new AFoo();
    }
};

class BFoo : Foo {
public:
    void bar() {
        // ...
    }

    static Foo* create() {
        return new AFoo();
    }
};

class FooFactory {
public:
    void register(std::string typeName, std::function<unique_ptr()> ctor) {
        registeredTypes[typeName] = ctor;
    }

    Foo* create(const std::string& typeName) {
        return registeredTypes[typeName]();
    }

private:
    std::unordered_map<std::string, std::function<Foo*()>> registeredTypes;
};

int main() {
    FooFactory factory = new FooFactory();
    factory.register("A", AFoo::Create);
    factory.register("B", BFoo::Create);

    Foo* = factory.create("A");
}

Prima di tutto, non sono proprio sicuro che "Factory" sia il nome giusto per questo modello. Esiste un nome migliore per lo schema di "Seleziona un tipo basato su una stringa e crea un'istanza di tipo"?

In secondo luogo, non mi piace la registrazione manuale dei tipi, ma non riesco a vedere nessun altro modo per farlo dato le informazioni di tipo run time limitate del C ++. Qualcuno può offrire una soluzione migliore che trovi automaticamente tutte le sottoclassi di Foo al momento della compilazione?

In terzo luogo, il mio manager e io non siamo d'accordo su dove dovrebbe essere il metodo factory. Preferirei averlo in Foo stesso, mentre a lui piace il modello attuale meglio. Tuttavia, nessuno di noi ha un argomento particolarmente strong. C'è una ragione sostanziale per preferire l'uno o l'altro?

    
posta Jason Watkins 19.04.2018 - 00:12
fonte

2 risposte

5
  1. Sì, Factory è il nome giusto per questo modello.
  2. No, C ++ non offre un modo per enumerare i tipi. Puoi forse ridurre il boilerplate necessario con alcune macro intelligenti, ma non lo suggerirei
  3. Il tuo manager ha ragione. Se inserisci il codice in Foo , diventerebbe uno stato globale e vorresti evitarlo. Avere un esplicito FooFactory ti consente di esaminare meglio queste informazioni.
risposta data 19.04.2018 - 10:18
fonte
1

Per le domande 1) e 2) Non posso dire molto di più che Sebastian Redl ha già detto così bene - "factory" è il nome giusto, e mentre c'è un modo tramite macro-voodo-magic (ad esempio il test di google il framework enumera tutti i test in proprio) dovresti prendere in considerazione due volte prima di farlo.

Come per la domanda 3) Posso solo indicare il principio di responsabilità singola - "Una classe dovrebbe hai solo un motivo per cambiare. " La responsabilità delle classi Foo è di fare bar() . Tenere una mappatura di tutte le potenziali sottoclassi di Foo e determinare quale sottoclasse di Foo creare è una responsabilità diversa. (Riconsiderare la mappatura con le stringhe. Mappare la stringa su enum durante il caricamento e usare quell'enum per mappare le classi - in questo modo non è necessario cospargere "A", "B," C "su tutto il codice E Riduci il rischio di bug - è molto più probabile che manchi un errore di battitura in una stringa piuttosto che in un enum.)

    
risposta data 20.04.2018 - 11:32
fonte

Leggi altre domande sui tag