Non sono sicuro di come configurare i miei dati per un sistema di waypoint

0

Ho un sistema che ho scritto su carta e sto cercando di scrivere questo in C # in un modo facile da usare.

Voglio una serie di waypoint collegati (dove i waypoint possono essere collegati a qualsiasi numero di altri waypoint).

Ma i waypoint possono essere solo un punto arbritratico lungo il percorso o un oggetto reale nel sistema con un certo comportamento (questi sono solitamente i bersagli e i punti di partenza).

Quindi ho configurato la struttura dei dati di base:

Waypoint¬ //struct
   List<Edge> Connections
   Vector3 Position
Edge¬ // struct
   Waypoint A
   Waypoint B
   Bool HasAnchor  //for curving to waypoint
   Vector3 AnchorPoint //bezier anchor point

Ora la confusione che ho è che ho 2 tipi di oggetti che devono essere contati come punti di passaggio. Si tratta di un "produttore" che produce agenti per viaggiare lungo i punti di passaggio, e un "consumatore" che è anche un punto di passaggio che riceve e rimuove gli agenti dal sistema.

E l'esempio sarebbe una rete elettrica, dove da un produttore è il generatore di energia, quindi un apparecchio come una TV è il consumatore. Ma sono ancora punti di passaggio su un grafico.

Come faccio a fare un tipo come un generatore di corrente o un televisore sia come waypoint che come tipo?

    
posta WDUK 20.04.2018 - 00:32
fonte

1 risposta

2

Prima di tutto, scattando al buio, i tuoi commenti su "struct" suggeriscono che forse stai pensando di usare struct s per questo: non funzionerà, perché definirebbe una struttura dati ricorsiva: devi definire il tuo grafico con i tipi di riferimento (ad es. classi e interfacce (anche se non di tipo tecnico di riferimento).

Se è possibile, il modo più bello per raggiungere il tuo obiettivo (a quanto ho capito) sarebbe quello di esporre il concetto di Waypoint attraverso un interfaccia , come questa:

interface IWaypoint
{
    IList<Edge> Connections { get; } // made this an IList'1 for good measure.
    Vector3 Position { get; }
}

class Edge
{
    public IWaypoint A { get; } // edge defined in terms of IWaypoints
    public IWaypoint B { get; }
    public bool HasAnchor { get; }
    public Vector3 AnchorPoint { get;}
}

In sostanza si definisce il proprio grafico in termini di spigoli e punti IWay: potrebbe anche astrarre i bordi (ad esempio in modo da poter definire strade, linee elettriche e tubi). Ora puoi avere le tue classi Waypoint , Producer e Consumer che implementano questa interfaccia.

class Waypoint : IWaypoint
{
    public IList<Edge> Connections { get; }
    public Vector3 Position { get; }
}

È possibile che Producs e Consumers ereditino direttamente da Waypoint, cosa che potrebbe semplificare l'implementazione, ma è possibile che non abbia senso (almeno non senza rendere i membri in Waypoint virtuale).

class PowerGenerator : Waypoint // extend Waypoint
{
    // stuff that is specific to PowerGenerator
}

Più laborioso, ma concettualmente più semplice / più pulito, è solo per fare in modo che ogni tipo riattivi i membri se necessario.

class PowerGenerator : IWaypoint // implement IWaypoint
{
    IList<Edge> Connections { get; }
    Vector3 Position { get; }

    // stuff that is specific to PowerGenerator
}

Il vantaggio principale di tutto questo è che qualsiasi codice che deve elaborare i Waypoint può invece gestire l'interfaccia IWaypoint , il che significa che puoi fornirli con qualsiasi tipo che li implementa. Ad esempio, un metodo di attraversamento grafico potrebbe avere una firma come questa:

/// <summary>
/// Given a start and end waypoint, computes the route with the fewest edges between the two
/// </summary>
Edge[] FindRoute(IWaypoint start, IWaypoint end);

Puoi passare tutto ciò che implementa IWaypoint come inizio o fine. Rende anche il tuo codice estensibile, perché chiunque può fornire una nuova classe che implementa IWaypoint , e funzionerà con il tuo codice. Come sempre nella programmazione, le interfacce sono solo uno strumento, e spetta a te come progettista del sistema selezionare uno strumento basato sulla tua comprensione del dominio: non possiamo rispondere a questo problema per te senza sapere che tipo di operazioni stai andando da eseguire sui grafici dei waypoint.

Alcuni vaganti seguono ...

Un "problema" con una sorta di astrazione è che è difficile fornire un comportamento ad-hoc in base al tipo di Waypoint (ad esempio con l'interfaccia corrente (semplice) IWaypoint , sarà un incubo fornire un costume comportamento per diversi tipi di waypoint (ad esempio se è necessario prendere una decisione in base al fatto che si tratti di un consumatore o di un prodotto). Aggiungere più interfacce e aggiungere altro alle proprie interfacce può risolvere in qualche modo questo problema, ma alcuni problemi semplicemente non può essere espresso dal fatto che i tuoi tipi forniscono un'interfaccia comune e questi problemi giustificano i sindacati, che sfortunatamente manca C #, quindi non entrerò nei dettagli.

Se sei nuovo al concetto di interfacce , allora potresti voglio fare un po 'di lettura; tuttavia, la maggior parte delle spiegazioni sul polimorfismo sono (a mio avviso) terribili e non riescono a trasmettere completamente il valore di tipi astratti come le interfacce: il vero valore (che può essere visto nel tuo esempio) deriva dalla definizione di un singolo insieme di comportamenti (il metodi sull'interfaccia) su cui il codice consumante (il codice che richiama dinamicamente i metodi sulle interfacce) e che implementa il codice (le classi che implementano l'interfaccia) dipendono entrambi, senza creare una dipendenza tra questi due tipi di componenti (ad es. puoi cambiare entrambi senza cambiare l'altro.) Nella tua istanza, puoi fornire molte implementazioni di IWaypoint senza modificare il tuo codice grafico-trasversale, e puoi scrivere un grafico di uso generale -verso il codice senza sapere nulla dei tipi in cui sarà effettivamente operativo in fase di runtime.

    
risposta data 20.04.2018 - 10:20
fonte

Leggi altre domande sui tag