2012-07-23 14 views
32

Ho notato che la mia dipendenza iniettata, codice pesante per l'osservatore (usando Guava EventBus) è spesso molto più difficile eseguire il debug rispetto al codice che ho scritto in passato senza queste funzionalità. In particolare quando si cerca di determinare quando e perché viene chiamato il codice dell'osservatore.Perché il modello di osservatore dovrebbe essere deprecato?

Martin Oderski e gli amici hanno scritto un lungo documento con un titolo particolarmente allettante, "Deprecating the Observer Pattern" e non ho ancora avuto il tempo di leggerlo.

Mi piacerebbe sapere cosa c'è di così sbagliato nel modello di osservatore e molto meglio delle (proposte o altre) alternative per condurre persone così brillanti a scrivere questo articolo.

Per cominciare, ho trovato una (divertente) critica del documento here.

+3

Discusso anche qui ... http://lambda-the-ultimate.org/node/4028 –

risposta

28

Citando direttamente the paper:

Per illustrare i problemi precisi del modello dell'osservatore, si comincia con una semplice e onnipresente esempio: trascinamento del mouse. L'esempio seguente traccia gli spostamenti del mouse durante un'operazione di trascinamento in un oggetto Path e visualizza sullo schermo. Per semplificare le cose, utilizziamo le chiusure Scala come osservatori.

var path: Path = null 
val moveObserver = { (event: MouseEvent) => 
    path.lineTo(event.position) 
    draw(path) 
} 
control.addMouseDownObserver { event => 
    path = new Path(event.position) 
    control.addMouseMoveObserver(moveObserver) 
} 
control.addMouseUpObserver { event => 
    control.removeMouseMoveObserver(moveObserver) 
    path.close() 
    draw(path) 
} 

L'esempio di cui sopra, e come avremo modo di discutere l'osservatore modello come definito in [25], in generale, viola un impressionante line-up di importanti principi dell'ingegneria del software:

effetti collaterali Gli osservatori promuovono effetti collaterali. Poiché gli osservatori sono senza stato, spesso abbiamo bisogno di alcuni di essi per simulare lo stato come nell'esempio di trascinamento. Dobbiamo salvare lo stato in cui è accessibile a tutti gli osservatori coinvolti come nella variabile path precedente.

Encapsulation Come variabile di stato path sfugge la portata degli osservatori, il modello dell'osservatore rompe incapsulamento.

Composability osservatori più formano una raccolta disomogenea di oggetti che si occupano di un singolo problema (o multipla, vedi punto successivo). Dal momento che più osservatori sono installati a punti diversi in momenti diversi, ad esempio , non è possibile, ad esempio, smaltirli completamente.

separazione degli interessi Gli osservatori sopra non solo tracce percorso mouse, ma anche chiamare un comando di disegno, o più in generale, comprende due preoccupazioni differenti nella stessa posizione del codice . Spesso è preferibile separare le preoccupazioni di costruire il percorso e visualizzarlo, ad esempio come nel modello model-view-controller (MVC) [30].

Scalabilità Potremmo realizzare una separazione degli interessi nel nostro esempio creando una classe per i percorsi che si pubblica eventi quando il tracciato cambia. Sfortunatamente, non esiste una garanzia per la coerenza dei dati nel modello di osservatore. Supponiamo di creare un altro evento che pubblica l'oggetto che dipende dalle modifiche nel nostro percorso originale, ad esempio un rettangolo che rappresenta i limiti del nostro percorso. Inoltre, considera un osservatore che ascolta i cambiamenti sia nel percorso sia nei suoi limiti per disegnare un percorso con cornice. L'osservatore avrebbe dovuto manualmente determinare se i limiti sono già aggiornati e, in caso contrario, rinviare l'operazione di disegno . Altrimenti l'utente può osservare un frame su lo schermo che ha la dimensione sbagliata (un glitch).

Uniformità diversi metodi per installare diversi osservatori codice diminuzione uniformità.

Astrazione C'è un basso livello di astrazione nell'esempio. Si basa su un'interfaccia pesante di una classe di controllo che fornisce più di semplici metodi specifici per installare osservatori di eventi del mouse . Pertanto, non possiamo astrarre sulle fonti di eventi precise. Ad esempio, potrebbe consentire all'utente di interrompere un'operazione di trascinamento premendo la chiave di escape o utilizzare un dispositivo di puntatore diverso, ad esempio uno schermo tattile o una tavoletta grafica touch .

Gestione risorse La durata di un osservatore deve essere gestita dai clienti. Per motivi di prestazioni, vogliamo osservare gli eventi di spostamento del mouse solo durante un'operazione di trascinamento . Pertanto, dobbiamo installare esplicitamente e disinstallare l'osservatore di spostamento del mouse e abbiamo bisogno di ricordare il punto di installazione (controllo sopra).

distanza semantica In definitiva, l'esempio è difficile capire perché il flusso di controllo viene invertito che si traduce in codice standard troppo che aumenta la distanza semantica tra l'intenzione programmatori e il codice effettivo.

[25] E. Gamma, R. Helm, R. Johnson e J. Vlissides. Modelli di disegno : elementi del software orientato agli oggetti riutilizzabile. Addison-Wesley Longman Publishing Co., Inc., Boston, MA, USA, 1995. ISBN 0-201-63361-2.

6

Credo che il modello di Osservatore abbia gli inconvenienti standard che derivano dal disaccoppiare le cose. Il soggetto viene disaccoppiato dall'osservatore ma non puoi semplicemente guardare il suo codice sorgente e scoprire chi lo osserva. Le dipendenze hardcoded sono di solito più facili da leggere e pensare, ma sono più difficili da modificare e riutilizzare. È un compromesso.

Per quanto riguarda la carta, non affronta il pattern Observer stesso ma un particolare utilizzo di esso. In particolare: più oggetti Osservatore senza stato per singolo oggetto osservato. Questo ha l'ovvio inconveniente degli osservatori separati che hanno bisogno di sincronizzarsi tra loro ("Poiché gli osservatori sono senza stato, spesso abbiamo bisogno di alcuni di essi per simulare lo stato come nell'esempio di trascinamento. Dobbiamo salvare lo stato in cui esso è accessibile a tutti gli osservatori coinvolti come nel percorso variabile sopra. ")

l'inconveniente di cui sopra è specifico per questo tipo di utilizzo, non al modello Observer stessa. Si potrebbe anche creare un oggetto osservatore singolo (stato!) Che implementa tutti i metodi , OnThat, OnWhatever ed eliminare il problema di simulare una macchina a stati su molti oggetti senza stato.

+0

Ma gli osservatori nell'esempio * do * hanno chiaramente effetti collaterali come menzionato nella citazione. (Vedi tutte le manipolazioni del 'percorso' def). –

6

Sarò breve perché sono nuovo all'argomento (e non ho ancora letto quell'articolo specifico).

Il pattern di osservatore è intuitivamente errato: l'oggetto da osservare sa chi sta osservando (oggetto <> - Observer). Questo è contro la vita reale (in scenari basati su eventi). Se urlo, non ho idea di chi stia ascoltando; se un fulmine colpisce il pavimento ... un fulmine non sa che c'è un pavimento finché non colpisce !. Solo gli osservatori sanno cosa possono osservare.

Quando accade questo genere di cose, il software è un disastro, perché costruito contro il nostro modo di pensare. È come se e l'oggetto sapesse quali altri oggetti possono chiamare i suoi metodi.

IMO un livello come "Ambiente" è l'incaricato di prendere gli eventi e di notificare l'interessato. (OPPURE mischia l'evento e il generatore di quell'evento)

Event-Source (Oggetto) genera eventi nell'ambiente. Ambiente consegna l'evento all'Observer. L'osservatore potrebbe registrarsi al tipo di eventi che lo riguardano o che è effettivamente definito nell'ambiente. Entrambe le possibilità hanno senso (ma volevo essere breve).

Nella mia comprensione il modello di osservatore mette insieme l'ambiente & soggetto.

PS. odio mettere in paragrafi idee astratte! : P

+0

Qui http://www.marco.panizza.name/dispenseTM/slides/exerc/eventNotifier/eventNotifier.html ho trovato lo schema che dice sostanzialmente lo stesso: -Editore (Salvo) -Subscriber (Object) -EventService (Ambiente) (1998) Dopo tutto il "buon senso" ci conduce ad esso e in un modo o nell'altro implementiamo questo tipo di middle-layer durante la programmazione. Il problema arriva quando il Pattern motiva o fuorvia. –

+0

I soggetti non conoscono i loro osservatori (forse solo attraverso la classe base). Il libro Design Pattern menziona anche un change manager. Questo è in qualche modo simile al tuo ambiente. Il pattern Imho the Observer è ottimo per la notifica di elementi GUI (indipendenti), ma lo schema presenta anche alcuni seri inconvenienti: notifiche spurie mentre il soggetto o il livello aziendale non si trova in uno stato coerente; soggetto a modifiche da parte di un osservatore durante un aggiornamento di notifica. – gast128

+0

Alcuni punti qui, il soggetto non sa nulla degli osservatori, possiamo ottenere questo tramite un'interfaccia astratta. –

Problemi correlati