Il modello Observer è adeguato per questo tipo di scenario?

2

Sto creando un semplice framework di sviluppo di giochi con Ruby.

C'è un sistema di nodi. Un nodo è un'entità di gioco e ha una posizione. Può avere nodi figli (e un nodo genitore). I bambini sono sempre disegnati relativamente ai loro genitori.

I nodi hanno un campo @position . Chiunque può modificarlo. Quando tale posizione viene modificata, il nodo deve aggiornare i suoi figli di conseguenza per disegnarli correttamente relativamente ad esso.

@position contiene un'istanza Point (una classe con proprietà x e y, più alcuni altri metodi utili).

Devo sapere quando cambia lo stato di @position di un nodo, quindi posso dire al nodo di aggiornare i suoi figli.

Questo è facile se il programmatore fa qualcosa del genere:

@node.position = Point.new(300,300)

Perché è equivalente a chiamare questo:

# Code in the Node class
def position=(newValue)
  @position = newValue
  update_my_children    # <--- I know that the position changed
end

Ma mi sono perso quando questo accade:

@node.position.x = 300

L'unico che conosce che la posizione modificata è l'istanza Point memorizzata nella proprietà @position del nodo. Ma ho bisogno che il nodo sia avvisato!

È stato a questo punto che ho considerato il pattern Observer . Fondamentalmente, Point è ora osservabile.

Quando a una proprietà position di un nodo viene assegnata una nuova istanza Point (tramite l'operatore di assegnazione), smetterà di osservare il Point precedente (se presente) e inizia a osservare quello nuovo. Quando un'istanza Point ottiene una modifica di stato, verranno notificati tutti gli osservatori (il nodo che lo possiede), quindi ora il mio nodo può aggiornare i suoi figli quando la posizione cambia.

Un problema è quando questo accade:

@someNode.position = @anotherNode.position

Ciò significa che due nodi stanno osservando lo stesso punto. Se cambio una delle posizioni del nodo, anche l'altra cambierebbe. Per risolvere questo problema, quando viene assegnata una posizione, ho intenzione di creare una nuova istanza Punto, copiare% s_dec% e% co_de dell'argomento passato e memorizzare il mio punto appena creato invece di memorizzare quello passato.

Un altro problema che temo è questo:

somePoint = @node.position
somePoint.x = 500

Questo, tecnicamente, modificerebbe la posizione di x . Non sono sicuro che qualcuno si aspetterebbe un comportamento tale . Ho l'impressione che le persone vedano y come una specie di primitivo piuttosto che un oggetto reale.

Questo approccio è anche ragionevole? Motivi per cui mi sento scettico:

  • Ho sentito che il pattern Observer dovrebbe essere usato con, beh, molti osservatori. Tecnicamente, in questo scenario c'è un solo osservatore alla volta.
  • Quando assegni la posizione di un nodo come un'altra ( @node ), dove creo un'intera nuova istanza piuttosto che archiviare il punto passato, ci si sente in forma o addirittura inefficiente.
posta Omega 14.07.2013 - 00:50
fonte

3 risposte

3

Potresti risolvere questo problema rendendo Point un oggetto immutabile. Gli oggetti immutabili sono oggetti con proprietà di sola lettura che sono impostate alla creazione e non possono cambiare durante la vita dell'oggetto. All'inizio questo potrebbe sembrare un limite, ma semplifica enormemente il codice perché hai meno effetto a distanza.

Quando è necessario modificare una posizione, si creerà un nuovo punto e lo si assegnerà. Potresti avere un metodo di utilità in Point per questo, come position.moveBy(3, -2) che non cambia l'oggetto Point stesso ma restituisce un nuovo oggetto Point con una posizione relativa a quella corrente.

    
risposta data 10.01.2014 - 10:25
fonte
0

Penso che manchi il lato osservatore (sottoscrizione) del pattern Observer. Dai un'occhiata al modulo Osservabile .

Potresti creare una classe ObservablePosition che gestisce la posizione di un nodo (getter, setter, ecc.) e notifica gli osservatori secondo necessità. I nodi figli si iscrivevano alle modifiche sull'OP del genitore. Ciò avrebbe l'effetto desiderato di far passare automaticamente una modifica del nodo a tutti i bambini nell'albero sottostante. Questo progetto potrebbe anche essere generalizzato per consentire ai nodi figlio di ascoltare le modifiche su più proprietà del nodo.

    
risposta data 14.07.2013 - 02:41
fonte
0

Perché non avere una classe o un metodo separato responsabile dell'aggiornamento del nodo e dei suoi figli con i nuovi valori. Puoi fare in modo che restituisca il nuovo valore per aggiornare il tuo riferimento e quindi è un calcolo semplice. Se segui questa strada, non devi preoccuparti di sapere chi è abbonato a chi e a tutto quel casino di stato.

    
risposta data 14.07.2013 - 03:05
fonte

Leggi altre domande sui tag