Design pattern per la modellazione di un PC

1

Ho un tipo di "PC" (cioè un personal computer) che ho bisogno di modellare in C ++ (posso usare standard di linguaggio nuovi come C++11 , ma non più recente di quello). In breve, abbiamo un sacco di granularità per i componenti nel PC (nel mio strumento attuale, sarebbe circa 10 volte il numero di componenti mostrati qui), cioè:

Tower
    Motherboard
        CPU
            CORE1
            CORE2
            CORE3
            CORE4
        RAM_BANK
            DIMM1
            DIMM2
            DIMM3
            DIMM4
        SATA_Controller
            Drive1
            Drive2
            Drive3
        PCIE_BUS
            VideoCard1
                VGA_OUT
                HDMI_OUT
                DVI_OUT
            VideoCard2
                VGA_OUT
                HDMI_OUT
    Power_Button

Vorrei impostare una classe base comune per tutti gli oggetti nella struttura sopra in modo da poter scorrere tutti gli oggetti che usano questa classe base comune. Idealmente, mi piacerebbe essere in grado di stampare l'albero ereditario sopra mostrato, nel modo più pulito possibile. Questo perché potrei dover supportare migliaia di "PC" diversi con diversi tipi di schede madri, controller del disco, tipi di CPU; alcuni modelli potrebbero avere componenti che altri non hanno, ecc.

Oltre a essere in grado di generare l'albero mostrato sopra, in modo generalizzato, ho una logica di rilevamento dei componenti che deve essere implementata. Ad esempio, la classe motherboard , dopo aver rilevato una versione specifica di una classe CPU , utilizzerà un'interfaccia specifica per comunicare con tale istanza di quella particolare versione della classe CPU , ad es. "La scheda madre ha rilevato una CPU AMD64, versione / modello XYZ, usa questa interfaccia per parlarci". L'obiettivo finale è un modo riutilizzabile per assemblare "PC" virtuali e assegnare automaticamente l'interfaccia appropriata affinché un genitore possa comunicare in modo bidirezionale con un oggetto figlio.

Quale modello di progettazione dovrei prendere in considerazione per una tale implementazione? Stavo pensando ad una semplice classe base comune (cioè la classe widget ) che tutte le altre classi ereditano. Quindi, la classe widget ha un tipo di dati astratto (elenco) che contiene un riferimento / puntatore a tutti gli altri membri di quella classe che ereditano anche dalla classe gen di widget . Tuttavia, non riesco a trovare un metodo per aggiungere automaticamente tutte le classi child %_de% -type all'elenco. Ad esempio:

class widget {
    private:
        std::list<widget> children;
    protected:
        char name[256];
    public:
        void announce()
        { printf("Component name:%s.", this->name);}
};

class MotherBoard: public widget {
    private:
        CPU cpu1;
        CPU cpu2;
        RAM_bank rambank1;
    public:
        MotherBoard() {
            // Add all classes that derive from widget to this list.
            // i.e. cpu1, cpu2, rambank1.
            // Also, construct 'cpu1' with a generic interface that
            // accepts 2 parameters: this.name (for this particular 
            // MotherBoard instantiation) and this->cpu1.name;
        }
};

class CPU: public widget {
    public:
        CORE core1;
        CORE core2;
        CORE core3;
        CORE core4;
};
class RAM_BANK: public widget {
    public:
        DIMM dimm1;
        DIMM dimm2;
        DIMM dimm3;
        DIMM dimm4;
};

Infine , lo stesso widget supporta l'introspection abbastanza per essere in grado di rilevare automaticamente tutti i membri che derivano da una classe specifica e aggiungerli alla lista C++ ? Questo è così che se un nuovo componente che eredita da children viene aggiunto come membro alla classe, le persone non possono dimenticare di averlo incluso nell'elenco widget .

Grazie.

    
posta Adder 06.12.2017 - 04:37
fonte

1 risposta

2

Struttura

Il buono

La tua Widget è una struttura ad albero, grazie alla lista di sotto-widget. Il vantaggio è che puoi sempre decomporre un Widget in parti più piccole. Questo è perfetto per rappresentare la struttura del tuo PC e navigare tra le parti.

Una variante poteva essere il modello di design composito , ma ciò non aggiungerebbe molti vantaggi qui, ad eccezione che dovresti differenziare i componenti che hanno sottocomponenti e componenti finali che non hanno.

Il cattivo

Ciò che manca, nel tuo modello è l'interfaccia bidirezionale . Il genitore conosce i suoi figli, ma i bambini non sanno dei loro genitori. QUINDI il bambino ha bisogno di un riferimento o di un puntatore al suo genitore. Devi adattare il processo di "assemblaggio" per ottenere questo

Un altro problema è che non usi il potenziale Widget nella sua misura massima. Ad esempio, il banco di memoria non dovrebbe avere solo 4 oggetti secondari; dovrebbe utilizzare anche l'elenco dei componenti (ad esempio aggiungere 4 DIMM all'elenco).

Il brutto

automatically assign the appropriate interface for a parent to communicate bi-directionally with a child object

Se "interfaccia" è intesa nel suo senso OO, stai bene. Tranne che l'interfaccia è solo l'interfaccia Widget . È abbastanza appropriato? (A proposito, non hai una funzione virtuale che possa adattare il loro comportamento a seconda della classe dell'oggetto.)

In caso contrario, o se "interfaccia" se è intesa nel significato del mondo dominio (ad esempio SATA, PCI, ecc.), allora non rispetti:

  • Se la CPU invia qualcosa al banco di memoria, il banco di memoria dovrebbe dialogare con i suoi figli in modo bus (cioè tutti i messaggi inviati alla banca vengono inviati a tutti i suoi figli).
  • il controller SATA del tuo modello non usa l'interfaccia SATA per dialogare con i suoi figli (e, a proposito, la S di SATA significa seriale, in modo che un bambino sia connesso al controller successivo e non al controller SATA).

Quindi, dopo la ristrutturazione per la componente bidirezionale e l'ulteriore, è possibile aggiungere ulteriori metodi per emulare le specifiche interfacce PC. Ma questo mette l'approccio Widget in questione, perché ogni sottoclasse di widget avrebbe un'interfaccia diversa e non si sarebbe mai sicuri di usare quella giusta! Per questo dovrai usare il polimorfismo e dynamic_cast , che non sarà un gioco da ragazzi ...

Struttura alternativa

Un design alternativo è quello di rimuovere la lista generale Widget dalla classe Widget e aggiungere una lista solo alle classi che ne hanno bisogno. Ad esempio il banco di memoria dovrebbe avere un elenco DIMM e il controller SATA un elenco DISK. Avrai comunque sempre l'interfaccia destra .

La navigazione all'interno della struttura sarebbe quindi meno facile: è ancora possibile prevedere i metodi in alto che inviano in modo ricorsivo ai bambini fino alla fine. Ma è necessario implementare il modello di visitatore se si desidera avere un algoritmo di esplorazione generalizzato per la propria struttura, una volta per stamparlo, un'altra per cercare un componente, ecc. (ognuno con un "visitatore" specifico)

Costruire la struttura

The end goal is a re-usable way to assemble virtual "PCs",

Per il momento, ti affidi ai costruttori per assemblare il PC. Se domani vuoi avere 4 DIMM ma 8? A cosa vuoi aggiungere un coprocessore? Come fai a sapere quanti dischi aggiungere quando crei un controller? Questo approccio non è realistico e non riutilizzabile.

Per poter costruire separatamente le parti e assemblarle, è necessario consultare il modello di utente . Perhap hai anche bisogno di un builder separato per ogni componente configurabile.

Interagire o non introspettare?

Con i due approcci (miglioramento del modello o dell'alternativa) e il costruttore, non è necessario eseguire alcuna introspezione.

Se ne hai bisogno in fase di runtime, devi rendere la tua classe polimorfica avendo almeno una funzione virtuale (ad esempio un distruttore virtuale nella classe base). Puoi cercare dynamic_cast , che è un approccio try-error all'introspezione. Oppure all'indirizzo type_info , ma che ha un uso limitato solo come nomi di tipi non standardizzati.

Al tempo di compilazione , c'è is_same e is_base_of , ma questo non ti aiuterà affatto nel tuo caso.

    
risposta data 06.12.2017 - 08:30
fonte

Leggi altre domande sui tag