Difficoltà a rendere questa classe aperta-chiusa

8

Ecco il mio problema: voglio leggere input da diversi dispositivi HID come un gamepad, gareggiare bene, joystick, ecc. Praticamente qualsiasi controller di gioco. Il problema è che hanno tutti input diversi.

Il gamepad ha pulsanti, interruttori e stick mentre il racing potrebbe avere una leva del cambio. Sono riuscito ad astrarre tutti questi diversi componenti in soli 3 così invece di avere una classe base con tutte le possibili combinazioni:

abstract class Device
    {
    public Buttons Buttons;
    public Axes Axes;
    public Switches Switches;
    public GearSticks GearSticks;
    //many more
    }

Ora posso avere:

abstract class Device
{
public Buttons Buttons;   //on or off
public Axes Axes;         //range [-100%:100%]
public Switches Switches; //multiple states
}

All'inizio ero contento di questo dato che sembrava coprire tutti i possibili tipi di input e quindi la mia classe può rimanere chiusa pur essendo aperta all'estensione attraverso tutte le implementazioni concrete poiché tutto può essere astratto a soli 3 tipi di input.

MA allora mi sono detto per me stesso se stavo solo ritardando l'inevitabile? Cosa succede se un giorno dovrò aggiungere un altro campo alla mia classe Device ? Non supporta qualcosa come una trackball!

C'è un modo in cui posso rendere questa lezione in futuro? Per come la vedo, mi ritrovo con qualcosa di simile:

public Device1 : Device
{
//buttons
//trackball
}

public Device2 : Device
{
//Switch
//Axis
}

public Device3 : Device
{
//trackball
//switch
}

E dovrei continuare ad aggiungere proprietà alla mia classe base ogni volta che c'è qualcosa di nuovo da implementare.

    
posta Mihai Bratulescu 04.09.2018 - 18:21
fonte

2 risposte

7

Sono abbastanza sicuro che ciò possa essere fatto introducendo un concetto come un InputChannel astratto e dispositivi che hanno un elenco configurabile di canali di input. Un canale di input avrà un nome, un tipo, forse alcuni metadati e dovrà essere in grado di produrre qualche "stato" che si adatti a quel tipo. Potrebbero esserci canali predefiniti come un pulsante, un'ascia o uno switch o qualche nuovo canale che al momento non conosci (ma potrebbe essere aggiunto in seguito introducendo una nuova classe child InputChannel ).

In questo modo, un dispositivo diventerà una sorta di meta-modello e avrai anche bisogno di un modo per gestire gli stati del dispositivo, che devono corrispondere all'elenco dei canali di input del dispositivo.

Tuttavia, questo tipo di approccio generico ha un certo rischio di overengineering, noto anche come Effetto piattaforma interna . Ad esempio, potrebbe non essere semplice aggiungere funzionalità specifiche a un dispositivo generico, o eventi specifici o interazioni tra canali di input differenti. Potrebbe anche essere più difficile da usare e capire per un utente della tua libreria di dispositivi generici.

Si noti che non è sempre vantaggioso creare la soluzione più astratta possibile. I requisiti in evoluzione dell'hardware richiedono in genere uno sforzo maggiore da implementare nell'hardware stesso rispetto al software corrispondente, quindi spesso è meglio attenersi a una soluzione più specifica nel software e modificare il software quando necessario.

    
risposta data 04.09.2018 - 19:44
fonte
3

L'idea alla base del principio di open-closed è che è meno probabile che si interrompano le funzionalità esistenti se si implementano nuove funzionalità attraverso l'ereditarietà piuttosto che la modifica di una classe esistente. E puoi farlo ereditando dal tuo Hid. In un anno e un paio di mesi è possibile creare un Hid2020 che eredita da Hid e aggiunge il supporto per la trackball che verrà inventata nel quarto trimestre del 2019. Dopo l'invenzione e la divulgazione del rilevatore di squeeze nel 2023 è possibile creare una classe Hid2024 che discende da Hid2019.

Questo sarebbe l'approccio difensivo. Ma sarebbe anche un po 'sciatto da una prospettiva di design pulito. Nel tuo caso non perderei il sonno oltre a violare O e cambiare semplicemente la classe base mentre il mondo intorno a te cambia. Non sembra che l'implementazione della trackball o di qualsiasi altro nuovo tipo di controllo influenzi il modo in cui gestisci la pressione dei pulsanti o cambia le modifiche di stato ora.

    
risposta data 04.09.2018 - 20:31
fonte

Leggi altre domande sui tag