Come si dovrebbero evitare riferimenti ad oggetti circolari quando ogni elemento in una collezione può eventualmente interagire con qualsiasi altro elemento?

3

Ho una classe chiamata Canvas che funge da contenitore per un numero di Rectangle .

Il Rectangle s ha il seguente comportamento:

  1. Possono essere spostati all'interno di Canvas .
  2. Possono essere ridimensionati.
  3. Non possono sovrapporsi, spostarsi l'uno sull'altro o oltrepassare i limiti di Canvas .
  4. Il lato di un rettangolo può essere attaccato al lato di un altro rettangolo. Il lato allegato di Rectangle sarà uguale alla posizione del lato a cui è stato collegato per tutto il tempo in cui è collegato ad esso. Questa è una relazione a senso unico in quanto il Rectangle a cui è stato assegnato non cambierà a causa di eventuali modifiche nel Rectangle allegato.

A mio parere, la posizione di Rectangle è una proprietà di quel Rectangle e la modifica della posizione di Rectangle dovrebbe consistere nell'impostazione di tale proprietà. Tenendo presente questo, a causa delle regole 3 e 4, ogni Rectangle deve essere in grado di determinare la posizione di ogni altro Rectangle sullo stesso Canvas e le dimensioni della Canvas stessa, il che significa che deve avere un riferimento al Canvas in cui è contenuto. Ciò sembra negativo a causa del riferimento circolare creato tra ogni Rectangle e il suo Canvas .

Ho anche giocato con l'idea che Rectangle s non dovrebbe contenere la logica che detta il loro movimento / ridimensionamento e invece di avere tutta quella logica in Canvas . Il Canvas sembra diventare in qualche modo un oggetto dio, contenente i mapping degli allegati per tutto Rectangle s e l'aggiornamento delle posizioni dovuto a loro quando una Rectangle si sposta oltre a esporre un'interfaccia che ti consente di spostare, aggiungere e allega Rectangle s. Rectangle s non fa altro che contenere dati.

Il mio più grande punto di confusione qui è che sembra che questo tipo di problema debba essere stato incontrato prima, ma per la vita di me non riesco a descriverlo in generale abbastanza da trovare un altro esempio. Ci sono degli schemi accettati che si potrebbero usare per affrontare questo o dovrò imparare ad amare i riferimenti circolari?

    
posta gitbox 07.11.2016 - 03:00
fonte

1 risposta

3

Ciò che descrivi è simile alla logica contenuta nei gestori di layout della GUI.

Un componente in una finestra non esegue il polling di altri componenti per vedere se è possibile ridimensionarlo: invece, il gestore di layout garantisce che i vincoli siano soddisfatti.

Piuttosto che aggiungere canvas o rettangolo con questa logica extra, perché non creare una terza classe che appartiene alla tela e ha la responsabilità di garantire che il layout sia legale?

Sembra che i requisiti della tua classe siano leggermente diversi da una tipica interfaccia grafica, in quanto i rettangoli sono responsabili del movimento. Quello che immagino è qualcosa del genere:

Canvas c = new Canvas();
c.setLayoutManager(new RectangleLayoutManager());
c.add(new Rectangle()); // repeat a few times

Quindi in qualunque codice si spostino i rettangoli, potresti avere qualcosa di simile a questo:

Coordinates c = ...;
Rectangle r = ...;
if (!getCanvas().getLayoutManager().requestMove(this, c)) {
  // Handle the case where a move or resize is not legal
}

Questo ha il vantaggio che ogni classe ha una responsabilità. Una tela è un contenitore. I rettangoli sono semplicemente rettangoli. Il gestore di layout gestisce la complessa logica di garantire che i rettangoli soddisfino i criteri di spostamento. Se i criteri fossero semplici, potrebbe non avere senso creare una nuova classe per gestirli. Ma i tuoi criteri sono abbastanza complessi da meritare l'overhead di un'altra classe.

    
risposta data 07.11.2016 - 03:11
fonte