Abstract responsibility from caller without introducing complexity
How can i abstract away that offsetting without introducing additional computational complexity?
L'astrazione è una forma di complessità. Possiamo discutere sul grado di complessità, ma mi aspetto che tutti concordino sul fatto che un'astrazione aggiunge una quantità non nulla di complessità a un codice base.
Tuttavia, sono d'accordo sul fatto che questo debba essere estratto da un chiamante.
How do i abstract away the offsetting without introducing computaional complexity?
Ancora una volta, è impossibile fare qualcosa che non richiede alcuno sforzo. Vorrei riformulare le tue aspettative in modo che tu minimizzi la complessità computazionale piuttosto che evitarlo.
- Every time worldPos change, go trough the data in each child apply the change. localPoints andlocalEdges would now be the actual positions in the world.
Questo non è un buon approccio. Stai facendo lo sforzo di convertire tutti i punti, anche se non sai nemmeno se avrai mai bisogno di loro.
Supponiamo che la posizione del mondo cambi, ricalcoli tutto (ad esempio 100 vettori). Sono richiesti solo due valori prima che la posizione del mondo cambi di nuovo e devi ricalcolare tutto di nuovo. Hai effettivamente eseguito 98 conversioni inutili.
- Store worldPos in each child aswell and use a custom getter that creates a copy of the desired list, apply the offset to each element in the list and return it
Questo è più vicino a quello che vuoi, ma non è buono. Ora stai memorizzando worldPos sia nel genitore che nel bambino. Cosa succede se ti dimentichi di aggiornare uno di loro?
Nella migliore delle ipotesi, hai dati duplicati e sei responsabile della sincronizzazione. Nel peggiore dei casi, gestisci male la sincronizzazione e ti strapperai i capelli cercando di eseguirne il debug.
Una semplice soluzione sarebbe quella di avere il child store come riferimento al suo genitore, dove è in grado di recuperare il valore (non duplicato).
Un'altra soluzione sarebbe quella di richiedere sempre i valori tramite il genitore , non tramite il bambino. La distinzione qui è contestuale. A volte è meglio accedere a un bambino tramite i suoi genitori. A volte è meglio usare direttamente il bambino e fare in modo che il bambino parli con i suoi genitori quando è necessario.
Suppongo che tu sia attualmente in uno scenario in cui i chiamanti hanno un riferimento al bambino, non al genitore.
Una seconda considerazione è come intendi accedere a questi elenchi. Hai intenzione di iterare su di loro? Stai cercando articoli specifici?
In base al tuo esempio, assumerò che tu stia eseguendo un'iterazione su di essi e, pertanto, non ti dispiacerà convertire l'intera lista quando si accede alla lista.
Avrai bisogno di qualcosa di simile:
public class Child {
private Parent parent;
public List<Vector2> LocalPoints;
public List<Vector2> LocalEdges;
public Child(parent)
{
this.parent = parent;
}
public List<Vector2> WorldPoints => LocalPoints.Select(localVector => parent.worldPos + localVector).ToList();
public List<Vector2> WorldEdges => LocalEdges.Select(localVector => parent.worldPos + localVector).ToList();
}
Questo fa quello che ti serve. Niente che tu non stia effettivamente memorizzando gli elenchi di "mondo". Stai semplicemente calcolandoli al volo, il che significa che non devi tenere traccia delle modifiche a parent.worldPos
. Ogni volta che lo calcoli al volo, lavorerai automaticamente con il valore corrente.
Se hai bisogno di ulteriore ottimizzazione delle prestazioni quando accedi a singoli articoli dall'elenco (volendo evitare di convertire gli elementi indesiderati), allora hai bisogno di una soluzione più complessa.
Un'ultima considerazione: il caching. Questa è un'arma a doppio taglio.
- Se i vettori vengono recuperati molte volte più del
worldPos
in realtà cambia, puoi ottenere alcuni guadagni in termini di prestazioni calcolando i valori una sola volta quando worldPos
cambia.
- Tuttavia, questo ha un costo enorme: dover gestire la memorizzazione nella cache. Ciò richiede uno sforzo di sviluppo considerevole in cambio di un minore sforzo di prestazioni .
- Se
worldPos
cambia più spesso di quanto si ottenga per i vettori, l'approccio "cache all" ridurrà le prestazioni invece di aumentarle.
- Avresti quindi bisogno di un sistema che memorizza i valori nella cache solo quando vengono richiesti per la prima volta, un altro livello di complessità oltre all'approccio "cache all".
Questo deve essere superato. Poiché la compensazione dei vettori non è un calcolo ingombrante (sta letteralmente facendo x1+x2
e y1+y2
, non guarderei il caching ora.
La complessità di sviluppo dell'implementazione della memorizzazione nella cache non supera la complessità di calcolo di alcune aggiunte di numeri extra.
L'ottimizzazione prematura di solito non è una buona cosa . Prendi nota del problema di prestazioni potenziale ma attendi finché non si presenta un problema di prestazioni effettivo e cerca il collo di bottiglia. Il collo di bottiglia potrebbe trovarsi in una posizione completamente diversa.