Sto scrivendo una libreria in C ++ che viene utilizzata dai clienti per interfacciarsi con l'hardware. Ci sono molti dispositivi diversi che devo supportare.
Per semplicità, supponiamo di avere 2 Widget, WidgetA e WidgetB, che sono dispositivi fisici. Entrambi i widget comunicano usando lo stesso protocollo e condividono molto in comune. Entrambi supportano 20 delle stesse impostazioni di configurazione generiche. Tuttavia, WidgetA supporta 10 impostazioni di configurazione univoche e WidgetB supporta diverse 10 impostazioni di configurazione univoche. WidgetB ha anche alcune funzioni uniche.
L'utente della mia libreria potrebbe sapere in anticipo quale Widget sta utilizzando (ad esempio, se un utente ha acquistato solo 1 Widget e voleva usare la mia libreria per comunicare con esso, probabilmente lo userebbe sapendo che devono solo comunicare con WidgetA). Tuttavia, ci sono altri scenari in cui l'utente vorrebbe scrivere un'applicazione che gestisce una varietà di widget. Il tipo di Widget dovrebbe essere determinato in fase di esecuzione interrogando il dispositivo reale.
Quindi la mia domanda è: Quale dovrebbe essere il design per questa libreria? Stavo pensando alle seguenti opzioni:
1) Solo forza bruta e metti tutte le funzioni in una classe Widget generica. Il widget fisico sarebbe stato controllato prima di eseguire un comando e si sarebbe verificato un errore nel tentativo di utilizzare una funzione non supportata dal dispositivo. Questo finisce per essere un sacco di funzioni in 1 classe, senza fine in vista come nuovi Widget devono essere supportati in futuro.
class Widget
{
void setAddress(int); //generic config setting
void setUniqueOption1(int); //config only supported by physical WidgetA's
void setUniqueOption2(int); //config only supported by physical WidgetB's
... //repeat for all config and functions supported by any Widget!
}
2) Aggiungi una classe separata per ogni Widget (o ogni Widget con caratteristiche uniche). Sembra una buona idea, ma gli utenti dovrebbero prima creare un Widget generico, quindi determinare il tipo di dispositivo fisico con cui stanno parlando, quindi creare la classe WidgetA specifica per accedere a tale funzionalità.
class Widget
{
void setAddress(int); //generic config setting
}
class WidgetA : public Widget
{
void setUniqueOption1(int); //config only supported by physical WidgetA's
}
class WidgetB: public Widget
{
void setUniqueOption2(int); //config only supported by physical WidgetB's
}
3) crea una pura classe ConfigOption virtuale. Crea classi di configurazione per ogni Widget che contiene opzioni che l'utente imposta tutto in una volta. L'utente utilizza solo la classe generica Widget che ha una funzione setCustomConfig che accetta queste classi di configurazione del widget personalizzato.
class Widget
{
void setAddress(int); //generic config setting
void setCustomConfig(const ConfigOption&); //used to set all custom config settings
}
class ConfigOption = 0;
class WidgetA_Config : public ConfigOption
{
//user sets all the options, then sends the object to the Widget::setCustomConfig
int optionA1;
int optionA2;
int optionA3;
}
class WidgetB_Config : public ConfigOption
{
int optionB1;
int optionB2;
}
Questa è la prima volta che cerco di scrivere una buona interfaccia per interfacciarmi con l'hardware, il che genera una chiave nella mia logica normale che uso per scrivere codice. Qualcuna di queste idee è l'approccio giusto? O c'è qualche disegno che mi manca?
In realtà, ci sono ~ 30 di questi Widget, e il potenziale per più ogni giorno. Alcuni sono simili al 99% di quelli che considererei il "Base Widget", mentre altri possono avere queste caratteristiche uniche (configurazione e funzionalità).