Implementazione di campi saggi per oggetto in una classe che compone una raccolta di oggetti

2

Contesto

Quando si implementa una classe, c'è una distinzione tra i campi che sono lì perché fanno parte di ciò che è l'oggetto e dei campi che ci sono perché sono necessari per implementare l'oggetto.

Ad esempio, se si sta implementando un ArrayList, si avrà un array che non fa parte di ciò che è un ArrayList ma è richiesto nell'implementazione. Questo è il punto di avere proprietà pubbliche e campi privati.

Il caso problematico

Tuttavia, mi trovo in una specie di strana situazione in cui l'implementazione è al di fuori della classe perché l'algoritmo interagisce con una raccolta di tale oggetto.

Il mio caso è un motore fisico. La mia classe Body ha proprietà pubbliche che hanno senso come Velocity, Position, Size ecc. Tuttavia, ora inizia ad avere proprietà che hanno senso solo se usate dalla classe World, che interagisce con una collezione di corpi. Ho campi come CollisionShifting (quanto il corpo è spostato dalla collisione), Collisioni, Movimento (velocità * delta, necessario per verificare le collisioni) ecc. E la lista sta crescendo.

Il problema è che più funzioni implemento in World, i campi più non intuitivi che devo aggiungere a Body. E questo è male perché chiunque voglia implementare l'interfaccia Body dovrà implementare quei campi e non saprà quale sia il loro scopo. Come qualcuno che implementa il corpo (e non il mondo), tutto ciò che ti interessa è dove si trova il tuo corpo e quanto velocemente lo fa. Vuoi anche ricevere una notifica quando si verificano collisioni ma non vuoi avere dettagli come la quantità di corpo spostata dalle collisioni nell'ultimo frame come proprietà.

Opzioni possibili

Quindi quello che mi piacerebbe fare è avere campi privati per Corpo per l'implementazione del Mondo nella classe Mondo, ma non mi piace il primo aspetto di questa opzione.

Potrei mappare ogni Corpo in una classe il cui unico scopo è completare il corpo nel Mondo:

Map<Body, HiddenFieldsOutOfTheModel> extraInfos;

Potrei farlo per ogni campo. Sarebbe un po 'più logico perché non avrei una strana classe fuori dal modello, ma penso che sia come spostare il problema:

Map<Body, Vector> collisionShiftings;
Map<Body, List<Collision>> collisionsPerBody;
//etc.

Questa opzione è un po 'noiosa perché ogni volta che il Mondo vuole rimuovere un corpo, deve rimuoverlo da una quantità variabile di Maps. Inoltre, ho bisogno di incapsulare le operazioni di aggiunta / rimozione mentre senza Maps posso semplicemente lasciare l'accesso in scrittura all'array.

Domanda

Devo dire che preferisco il secondo approccio, ma c'è qualcosa di meglio? Qual è la soluzione migliore per mantenere il modello chiaro e confondere meno persone possibile?

In breve, qual è il modo migliore per avere campi privati per oggetto in una classe contenente una raccolta di questi oggetti?

Aggiornamento

È passato un po 'di tempo da quando ho fatto questa domanda, ma non ho ancora una "soluzione perfetta". (E non sono sicuro che ne troverò mai uno) Per ora ho preso l'opzione Map<Body, HiddenFieldsOutOfTheModel> extraInfos; e ho chiamato il mio HiddenFieldsOutOfTheModel class BodyState .

    
posta Winter 17.06.2017 - 02:47
fonte

2 risposte

1

Il mio corpo non sa dove sia.

Il mio corpo non sa quanto velocemente si sta muovendo.

Il mio corpo sa che sta vivendo 1g di accelerazione. Ma è solo perché è in collisione con la sedia su cui sono seduto. Questo mi sta comprimendo leggermente la colonna vertebrale e mi fa intorpidire il sedere.

Mi piace molto rimuovere dagli oggetti ciò che non hanno bisogno di sapere. Certo, se guardo in giro nella stanza vedo molti altri oggetti a distanze misurabili e velocità da me, ma questo è il loro problema.

Il nome elegante di dove sono io è chiamato una cornice di riferimento. Ogni oggetto ha il diritto di pensare a se stesso come a riposo. Sono i fotogrammi di riferimento che si muovono.

Ecco un piccolo sito web avvincente che cerca di insegnare questa idea con un gioco chiamato Relativistic Space Sheep . Non a partire da Asteroids ho visto una lezione migliore sulla fisica trasformata in un gioco.

Hai già colto l'idea di separare queste cose ma non sei sicuro di dove metterle. Mi piace usare un frame di riferimento per tenere traccia del resto. Tutto è misurato in relazione ad esso. Solo lui conosce le posizioni e le velocità. Da esso puoi trovare tutto il resto.

    
risposta data 17.06.2017 - 04:13
fonte
0

Permetti al chiamante di specificare i campi che desidera in un oggetto "modello", quindi restituisci un handle o un riferimento all'oggetto reale. Se fosse c #, il codice del chiamante sarebbe simile a

class Rock : IGameObjectTemplate
{
    //Blah blah blah
}

var rock = new Rock
{
    Position = new Point(10,10),
    Mass = 100
};
var worldObject = motionEngine.CreateObject(rock);

O se vuoi renderlo più facile, elimina completamente l'oggetto del chiamante e imposta i parametri necessari in un metodo factory:

var worldObject = motionEngine.CreateRock(10, 10, 100);

In questo modo, il motore gestisce ancora la creazione e il tracciamento di tutti gli oggetti del mondo, ma il chiamante può anche avere una copia se (s) vuole. L'istanza restituita può essere un tipo completamente separato con tutti i campi necessari, pubblici, privati o interni.

    
risposta data 14.04.2018 - 03:43
fonte