Uso inefficiente delle interfacce in OOP (C #)

1

Nel mio codice, ho due interfacce, diciamo IOpenable e IExaminable . IOpenable consente all'utente di Open o Close dell'oggetto e IExaminable consente all'utente di Examine dell'oggetto.

Ora abbiamo una sorta di struttura Tile che contiene oggetti che rispettano quanto segue: Non tutti gli oggetti sono apribili, non tutti gli oggetti sono esaminabili, altri sono entrambi.

Quando l'utente fa clic con il tasto destro su Tile in-map, desidero popolare una sorta di elenco con i possibili obiettivi e le loro varie funzionalità.

Come esempio concreto, diciamo che un Book è esaminabile e apribile, mentre un Card è appena esaminabile. Quando facevo clic con il tasto destro, volevo farlo in modo da poter navigare attraverso Apri - > Prenota o esamina - > [Card | Libro].

Al momento, sono essenzialmente copia / incolla del codice, dove valuto ogni volta se qualche oggetto è IOpenable e lo aggiungo a un elenco di Open target. Quindi faccio lo stesso per Close , poi IExaminable con Examine . Ad esempio lego la funzionalità del pulsante a un delegato, ad es. [Apri - > Book] avrebbe la funzionalità

delegate 
{
    lockedInteractable.Open(); 
}

Il problema è che sto riutilizzando lo stesso codice ogni volta, semplicemente cambiando l'interfaccia che stiamo cercando (ad esempio cambiando IOpenable in IExaminable ) e cambiando la funzione nel delegato (ad esempio% da.Open() a .Examine() o qualsiasi altra cosa).

C'è un modo più efficiente per farlo? È semplicemente un prodotto della mia cattiva pratica di codice nel rendere le cose implementabili IOpenable e IExaminable in questo modo?

Chiarimento

Nella mia configurazione, i risultati di Apertura in uno spostamento di sprite, proprio come la chiusura (non voglio fare di questa funzionalità di commutazione) e l'esame prende effettivamente una stringa e genera alcuni testi di sapore sull'oggetto, ad es. "[Bob] ha esaminato la [porta] e ha trovato che è molto disinteressato."

La duplicazione del codice è essenzialmente la seguente:

Inizio creando un'istanza di Button per ogni esaminabile. Button quindi ha l'evento on-click collegato a .Examine per quell'oggetto esaminabile. Facciamo quindi un'istanza di Button che apre il menu con tutti i pulsanti precedentemente creati e ha il testo da esaminare. In questo modo, abbiamo impostato un menu con Examine - > Target come descritto in precedenza.

Quindi creo un'istanza di Button per ogni apertura. Button quindi ha l'evento on-click collegato a .Open per quello ...

ecc. per ogni operazione e funzione possibili.

Speravo di trovare un modo per passare semplicemente, diciamo, IExaminable o IOpenable e quale parte voglio inserire in un menu, ad es. .Open e crea automaticamente un menu, piuttosto che duplicare ripetutamente il codice e cambiare solo il metodo e l'interfaccia.

Codice

if(tileInteractable is ILock)
{
        ILock lockedInteractable = tileInteractable as ILock;
        if(lockedInteractable.Locked)
        {
            int lockedItemCount = 0;
            List<string> lockedStrings = new List<string>();
            List<Action> lockedActions = new List<Action>();
            lockedItemCount++;
            lockedStrings.Add (tileInteractable.ObjectName);
            lockedActions.Add(new Action(
                                delegate 
                                {
                                lockedInteractable.Unlock (GameManager.instance.player.entity); 
                                Reset();
                                }
                            ));
            radComponentCount++;
            buttonStrings.Add ("Unlock");
            actions.Add(new Action(
                                delegate 
                                {
                                Reset();
                                GenerateRadial(lockedItemCount,lockedActions,lockedStrings);
                                isActive = true;
                                }
                            ));
        }
}

Per eseguire l'utente attraverso il codice, si verifica quanto segue:

Viene creato un pulsante del menu radiale. Si dice di creare un pulsante con il nome dell'entità come testo al passaggio del mouse.

Se premuto, richiama Unlock con il mittente come giocatore, quindi chiude il menu radiale tramite Reset() .

Creiamo quindi un altro pulsante radiale etichettato Unlock che esegue l'altro menu radiale quando viene premuto. Questo pulsante radiale viene quindi integrato in un menu di base con altri simili, quindi il primo menu ha Unlock , Examine , ecc. Se esiste qualcosa che implementa tale funzionalità e il secondo si riferisce ai potenziali obiettivi.

Questo codice è quindi quasi identicamente duplicato, con ILock cambiato in IExaminable e .Unlock cambiato in .Examine . In questo modo si crea la funzionalità Esamina per il menu principale radiale.

    
posta user188644 26.07.2015 - 09:34
fonte

1 risposta

1

Le interfacce sono uno strumento statico che consente ai programmatori di garantire quali metodi supporta un oggetto.

Stai provando a utilizzarli come meccanismo dinamico per consentire agli utenti - o, più precisamente, all'interfaccia utente - di inferire il azioni che gli utenti possono fare sull'oggetto.

Ciò di cui hai bisogno è un modo uniforme per accedere a livello di programmazione all'elenco di azioni in fase di runtime, in modo che il codice che crea l'interfaccia utente sia in grado di scorrere le azioni consentite e creare pulsanti per loro senza preoccuparsi di ciò che fa ciascuna azione specifica.

Ci sono due modi per farlo:

  1. Non utilizzare IOpenable e IExaminable , e invece ogni oggetto (o tipo di oggetto) contiene una tabella di azioni consentite, che puoi registrare manualmente.

  2. Usa la riflessione. Fondamentalmente vuoi segnare in qualche modo i metodi Open , Close e Examine , e fare in modo che l'interfaccia utente usi il reflection per ottenere questi metodi e convertirli in pulsanti per l'utente. La marcatura può essere eseguita in molti modi (a seconda di cosa supporta la lingua) - puoi dipendere dalla firma, usare annotazioni, usare nomi speciali, usare i membri del compagno, posizionare la marcatura sulle interfacce che i metodi hanno origine ... come puoi distinguere i metodi di azione dell'utente senza specificare ognuno nel codice di generazione dell'interfaccia utente.

risposta data 26.07.2015 - 15:16
fonte

Leggi altre domande sui tag