Observator (model de design)
Versiunea actuală a paginii nu a fost încă examinată de colaboratori experimentați și poate diferi semnificativ de
versiunea revizuită pe 19 mai 2019; verificările necesită
15 modificări .
Observator |
---|
Observator |
|
Tip de |
comportamental |
Scop |
- Modelul Observer definește o dependență unu-la-mulți între obiecte, astfel încât atunci când starea unui obiect se schimbă, toate obiectele care depind de acesta sunt notificate și actualizate automat;
- Modelul Observer încapsulează componenta principală (independentă) în abstractizarea Subiectului și componentele mutabile (dependente) în ierarhia Observator;
- Modelul Observer definește partea „View” a unui model Model-View-Controller (MVC) [1] .
|
Descris în Design Patterns |
da |
The Observer este un model de design comportamental . Cunoscuți și ca „subordonați” ( ing. Dependents ). Implementează un mecanism de clasă care permite unui obiect din această clasă să primească notificări despre modificările stării altor obiecte și astfel să le observe [2] .
Clasele la ale căror evenimente sunt abonate alte clase se numesc Subiecte, iar clasele abonate se numesc Observatori
[ 3 ] .
Șabloane similare: „ editor-abonat ”, „ intermediar ”, „ singuratic ”.
Numire
Definește o dependență unu-la-mulți între obiecte, astfel încât, atunci când starea unui obiect se schimbă, toți cei dependenți de acesta sunt notificați despre eveniment.
Implementare
La implementarea modelului de observator, sunt utilizate în mod obișnuit următoarele clase:
- Observabil - o interfață care definește metode pentru adăugarea, eliminarea și notificarea observatorilor;
- Observator - interfața prin care observatorul primește notificarea;
- ConcreteObservable este o clasă concretă care implementează interfața Observable;
- ConcreteObserver este o clasă concretă care implementează interfața Observer.
Domeniul de aplicare
Modelul de observator este utilizat atunci când sistemul are următoarele proprietăți:
- există cel puțin un obiect care trimite mesaje;
- există cel puțin un destinatar de mesaje, iar numărul și compoziția acestora se pot schimba în timp ce aplicația rulează;
- evită cuplarea puternică a claselor care interacționează.
Acest tipar este adesea folosit în situațiile în care expeditorul mesajelor nu este interesat de ceea ce fac destinatarii cu informațiile care le sunt furnizate.
Exemple
Text sursă în limba php
/**
* PHP oferă suport încorporat pentru acest model prin extensia inclusă
* SPL (Standard PHP Library):
* SplObserver - interfață pentru Observer (observator),
* SplSubject - interfață pentru Observable (observabil),
* SplObjectStorage - clasa auxiliară (oferă salvarea și ștergerea îmbunătățite
a obiectelor *, în special, sunt implementate metodele attach() și detach()).
*/
class Instrumente observabile SplSubject { private $storage ;
function __construct ()
{
$this -> storage = new SplObjectStorage ();
}
function attach ( SplObserver $observator )
{
$this -> storage -> attach ( $observator );
}
function detach ( SplObserver $observator )
{
$this -> storage -> detach ( $observator );
}
function notify ()
{
foreach ( $this -> storage as $obj )
{
$obj -> update ( $this );
}
}
}
clasa ConcreteObserver implementeaza SplObserver
{
private $observabil ;
private $index ;
function __construct ( Observabil $observabil )
{
static $sindex = 0 ;
$this -> index = $sindex ++ ;
$acest -> observabil = $observabil ;
$observabil -> atașați ( $acest );
}
function update ( SplSubject $subiect )
{
if ( $subiect === $this -> observable )
{
echo "Trimite notificare catre ConcreteObserver [ $this->index ] \n " ;
}
}
}
$observabil = nou Observabil ();
nou ConcreteObserver ( $observable );
nou ConcreteObserver ( $observable );
nou ConcreteObserver ( $observable );
$observabil -> notifica ();
Text sursă în limba php
interfață Observer
{
function notify ( $obj );
}
clasa Rata de schimb
{
static private $instanta = NULL ;
private $observers = matrice ();
privat $rată_schimb ;
funcție privată __construct ()
{}
funcție privată __clone ()
{}
static public function getInstance ()
{
if ( self :: $instance == NULL )
{
self :: $instance = new ExchangeRate ();
}
return self :: $instanta ;
}
public function getExchangeRate ()
{
return $this -> exchange_rate ;
}
public function setExchangeRate ( $new_rate )
{
$this -> exchange_rate = $new_rate ;
$this -> notifyObservers ();
}
public function registerObserver ( Observator $obj )
{
$this -> observatori [] = $obj ;
}
function notifyObservers ()
{
foreach ( $this -> observatori ca $obj )
{
$obj -> notify ( $this );
}
}
}
clasa ProductItem implementează Observer
{
public function __construct ()
{
ExchangeRate :: getInstance () -> registerObserver ( $this );
}
public function notify ( $obj )
{
if ( $obj instanceof ExchangeRate )
{
// Actualizați datele cursului de schimb
print "Actualizare primită! \n " ;
}
}
}
$produs1 = nou ProductItem ();
$produs2 = nou ProductItem ();
ExchangeRate :: getInstance () -> setExchangeRate ( 4.5 );
Text sursă în C#
folosind System ;
folosind System.Collections ;
folosind System.Collections.Generic ;
folosind System.Threading ;
namespace Observer
{
/// <summary>
/// Observer Pattern Judith Bishop ian 2007
/// Actualizat de Kobel' Bohdan 2013
///
/// Subiectul rulează într-un fir și își schimbă starea
/// independent. La fiecare schimbare, își anunță observatorii.
/// </summary>
class Program
{
static void Main ( string [] args )
{
Subject subject = new Subject ();
Observator observator = nou Observator ( subiect , „Centru” , „\t\t” );
Observator observator2 = nou Observator ( subiect , „Dreapta” , „\t\t\t\t” );
subiect . merge ();
// Așteptați
Consola utilizatorului . citește ();
}
}
Simulator de clasă : IEnumerable
{
șir [] mută = { "5" , "3" , "1" , "6" , "7" };
public IEnumerator GetEnumerator ()
{
foreach ( element șir în mișcări ) yield return element ; } }
interfață ISubject
{
void AddObserver ( observator IObserver ); void RemoveObserver ( observator IObserver ); void NotifyObservers ( șir s ); }
class Subiect : ISubject
{
public string SubjectState { get ; set ; }
Public List < IObserver > Observatori { get ; set privat ; }
Simulator privat Simulator ;
private const int viteză = 200 ;
public Subiect ()
{
Observatori = listă nouă < IObserver >(); simulator = simulator nou (); }
public void AddObserver ( observator IObserver ) { Observatori . Adăugați ( observator ); }
public void RemoveObserver ( observator IObserver ) { Observatori . Eliminați ( observator ); }
public void NotifyObservers ( șir s )
{
foreach ( var observator în Observers )
{
observator . Actualizare ( e );
}
}
public void Go ()
{
new Thread ( new ThreadStart ( Run )). Start ( );
}
void Run ()
{
foreach ( șir de caractere în simulator )
{
Consolă . WriteLine ( "Subiect: " + s );
SubjectState = s ;
NotifyObservers ( s );
fir . somn ( viteza ); // milisecunde
}
}
}
interfață IObserver
{
void Update ( stare șir ); }
class Observer : IObserver
{
string name ;
Isubiect ; _
starea șirului ;
decalaj al șirului ;
public Observer ( subiect IS , nume de șir , decalaj de șir ) { this . subiect = subiect ; aceasta . nume = nume ; aceasta . gap = decalaj ; subiect . AddObserver ( aceasta ); }
public void Actualizare ( șir subiectState )
{
stat = subiectState ;
Consola . WriteLine ( decalaj + nume + ": " + stare );
}
}
}
Sursa Java
// Exemplul descrie cum să primiți date de la o stație meteo (clasa WeatherData, dispecer de evenimente) și
//utilizați-l pentru a le afișa pe ecran (clasa CurrentConditionsDisplay, ascultător de evenimente).
//Ascultătorul este înregistrat cu observatorul folosind metoda registerObserver (în acest caz, ascultătorul este adăugat la lista de observatori).
//Înregistrarea are loc în momentul în care este creat obiectul currentDisplay, deoarece metoda registerObserver este aplicată în constructor.
//Când datele meteorologice se modifică, este apelată metoda notifyObservers, care la rândul său apelează metoda de actualizare
//pe toți ascultătorii, transmițându-le datele actualizate.
import java.util.LinkedList ;
import java.util.List ;
public class WeatherStation {
public static void main ( String [] args ) {
WeatherData weatherData = new WeatherData ();
Observer currentDisplay = new CurrentConditionsDisplay ();
Date meteo . registerObserver ( currentDisplay );
Date meteo . setMeasurements ( 29 f , 65 f , 745 );
Date meteo . setMeasurements ( 39 f , 70 f , 760 );
Date meteo . setMeasurements ( 42 f , 72 f , 763 );
}
}
interfață Observer {
void update ( temperatura float , umiditate float , presiune int ); }
interfață Observabil {
void registerObserver ( Observer o );
void removeObserver ( Observer o );
void notifyObservers ();
}
clasa WeatherData implementează Observable {
private List < Observer > observatori ;
temperatura plutitorului privat ; umiditatea flotorului privat ; private int presiune ;
public WeatherData () {
observatori = new LinkedList <> ();
}
@Override
public void registerObserver ( Observator o ) {
observatori . adaugă ( o );
}
@Override
public void removeObserver ( Observator o ) {
observatori . elimina ( o );
}
@Override
public void notifyObservers () {
pentru ( observator observator : observatori )
observator . actualizare ( temperatura , umiditate , presiune );
}
public void setMeasurements ( temperatura float , umiditate float , presiune int ) { asta . temperatura = temperatura ; aceasta . umiditate = umiditate ; aceasta . presiune = presiune ; notifyObservers (); } }
class CurrentConditionsDisplay implements Observer {
private float temperature ;
umiditatea flotorului privat ; private int presiune ;
@Override
public void update ( temperatura float , umiditate float , presiune int ) { aceasta . temperatura = temperatura ; aceasta . umiditate = umiditate ; aceasta . presiune = presiune ; afișaj (); }
public void display () {
System . afară . printf ( "Acum valorile sunt: %.1f grade Celsius si %.1f %% umiditate. Presiune %d mmHg\n" , temperatura , umiditatea , presiunea );
}
}
Text sursă în C++
#include <iostream>
#include <șir>
#include <listă>
folosind namespace std ;
clasa SupervisedString ;
clasa IObserver
{
public :
virtual void handleEvent ( const SupervisedString & ) = 0 ;
};
class SupervisedString // Clasa observabilă {
string_str ; _
lista < IObserver *> _observatori ;
void _Notifică ()
{
pentru ( auto & observator : _observers )
{
observator -> handleEvent ( * this );
}
}
public :
void add ( IObserver și ref )
{
_observatori . push_back ( & ref );
}
void remove ( IObserver și ref )
{
_observatori . eliminați ( & ref );
}
const string & get () const
{
return_str ; _
}
void reset ( șir str )
{
_str = str ;
_Notifică ();
}
};
class Reflector : public IObserver // Imprimă șirul observat în cout {
public :
virtual void handleEvent ( const SupervisedString și ref )
{
cout << ref . get () << endl ;
}
};
class Counter : public IObserver // Imprimă lungimea șirului observat în cout {
public :
virtual void handleEvent ( const SupervisedString și ref )
{
cout << "lungime = " << ref . obține (). lungime () << endl ;
}
};
int main ()
{
SupervisedString str ;
reflector refl ;
Contor cnt ;
str . adaugă ( refl );
str . resetare ( "Bună ziua, lume!" );
cout << endl ;
str . elimina ( refl );
str . adaugă ( cnt );
str . resetare ( „Lumea, Bună!” );
cout << endl ;
returnează 0 ;
}
Text sursă în ActionScript
//file IObserver.as
package
{
public interface IObserver
{
function notify ( obj : Object ): void ;
}
}
//fișier ExchangeRate.as
pachet
{
public class ExchangeRate
{
private static var _instance : ExchangeRate = null ;
observatori var privați : Array = []; private var _exchangeRate : Obiect ;
public function Rata de schimb ()
{
if ( _instance == null ) throw new Error ( 'Model Singleton!' );
}
funcția publică statică getInstance (): ExchangeRate { if ( _instance == null ) _instance = new ExchangeRate (); return _instanță ; }
public function get exchangeRate (): Object
{
return _changeRate ;
}
set de funcții publice exchangeRate ( value : Object ): void { _exchangeRate = value ; aceasta . notifyObservers (); }
funcția publică registerObserver ( valoare : IObserver ): void
{
this . observatori . push ( valoare );
}
private function notifyObservers (): void
{
for each ( var observator : IObserver in this . observatori )
{
observator . notifica ( acesta );
}
}
}
}
//fișier ProductItem.as
pachet
{
public class ProductItem implementează IObserver
{
public function ProductItem ()
{
ExchangeRate . getInstance (). registerObserver ( aceasta );
}
public function notify ( value : Object ): void
{
if ( valoarea este ExchangeRate )
{
var exchange : ExchangeRate = valoare ca ExchangeRate ;
urmă ( exchange.exchangeRate ) ; _ } } } }
//file Main.as
package
{
import flash.display.Sprite ;
public class Main extinde Sprite
{
public function Main (): void
{
var item1 : ProductItem = new ProductItem ();
var item2 : ProductItem = nou ProductItem ();
Rata de schimb . getInstance (). Rata de schimb = 3,5 ;
}
}
}
Text sursă în limba VB.NET
Imports System.Colelections
Imports System.Threading
Namespace Observer
''' <rezumat>
''' Observer Pattern Judith Bishop Ian 2007
'''
''' Subiectul rulează într-un fir și își schimbă starea
''' independent. La fiecare schimbare, își anunță observatorii.
''' </summary>
Class Program
Shared Sub Main ()
Dim subiect ca nou subiect ()
Dim Observer ca nou observator ( subiect , „Centru” , vbTab și vbTab )
Dim observator2 ca nou observator ( subiect , „Dreapta” , vbTab & vbTab & vbTab & vbTab )
subiect . du-te ()
' Așteptați
Consola utilizator . Citiți ()
End Sub
termina clasa
Simulatorul
de clasă implementează IEnumerable
Mișcări private ca șir () = { "5" , "3" , "1" , "6" , "7" }
Funcția publică GetEnumerator () Ca IEnumerator implementează IEnumerable . GetEnumerator
Returnează mișcările . GetEnumerator ' // Randamentul
funcției End End Class
Subiectul
clasei Delegat public Sub apel invers ( ByVal s As String )
Eveniment public Notificare ca apel invers
Simulator privat ca simulator nou () Private m_SubjectState As String Private Const speed As Integer = 200
Proprietatea publică SubjectState () As String
Get
Return m_SubjectState
End Get
Set ( ByVal value As String )
m_SubjectState = value
End Set
End Proprietate
Public Sub Go ()
Apel ( New Thread ( New ThreadStart ( AddressOf Run ))). Start ()
End Sub
Private Sub Run ()
Pentru fiecare s ca șir în consola simulatorului
. WriteLine ( "Subiect: " & s ) SubjectState = s RaiseEvent Notify ( e ) ' milisecunde Thread . Sleep ( viteză ) Next End Sub End Class
Interfață IObserver
Sub Update ( ByVal state As String )
End Interface
Class Observer
implementează IObserver
Nume privat As String
Subiect privat As Subiect Stat privat As String Gap privat As String
Subiect public Nou ( Subiect ByVal ca subiect , numele ByVal ca șir , decalajul ByVal ca șir ) Eu . subiect = subiect Eu . nume = numesc pe mine . gap = gap AddHandler subiect . Notificare , AddressOf Update End Sub
Actualizare publică sub ( ByVal subjectState As String ) Implementează IObserver . Actualizare stare = subjectStateConsole . _ WriteLine ( gap & name & ": " & state ) End Sub End Class End Namespace
Cod sursă în Python
din abc import ABCMeta , abstractmethod
Class Observer ( metaclass = ABCMeta ):
"""
Observator abstract
"""
@abstractmethod
def update ( self , message : str ) -> None :
"""
Obțineți mesajul nou
"""
pass
clasa Observabil ( metaclasa = ABCMeta ):
"""
Observabil abstract
"""
def __init__ ( self ) -> None :
"""
Constructor.
"""
self . observatori = [] # initializarea listei de observatori
def register ( self , observator : Observer ) -> None :
"""
Înregistrează un nou observator pentru a se abona la
"""
self . observatori . anexează ( observator )
def notify_observers ( self , message : str ) -> None :
"""
Trimite un mesaj tuturor observatorilor abonați la evenimentele
obiectului dat din clasa observabilă
"""
pentru observator în sine . observatori :
observator . actualizare ( mesaj )
Class Newspaper ( Observabil ):
"""
Un ziar care este urmat de mii de oameni
"""
def add_news ( self , news : str ) -> None :
""" Nou comunicat de
presă
"""
self . notify_observers ( stiri )
Class Citizen ( Observator ):
"""
Un cetățean obișnuit căruia îi place să citească ziarul preferat dimineața
"""
def __init__ ( self , name : str ) -> None :
"""
Constructor.
:param name: numele cetateanului, pentru a nu-l confunda cu altcineva """
self .name = nume
def update ( self , message : str ) -> None :
"""
Primirea următoarelor știri
"""
print ( f ' { self . name } a aflat următoarele: { mesaj } ' )
if __name__ == '__main__' :
newspaper = Newspaper () # creați un mic ziar de
ziar . înregistrare ( Cetăţean ( 'Ivan' )) # adăugaţi două persoane care sunt
ziar . înregistrare ( Cetăţean ( 'Vasily' )) # ... este abonat în mod regulat
# ... și aruncăm un alt ziar ziar
rață . add_news ( 'Observator - Model de design comportamental' )
'''
Ivan a învățat următoarele: Observator - Model de design comportamental
Vasily a învățat următoarele: Observator - Model de design comportamental
'''
Text sursă în Object Pascal (Delphi)
observator de program ;
/// Modelul observatorului Judith Bishop ian 2007
/// Portat la Pascal de Dmitry Boyarintsev, mai 2018
///
/// Subiectul rulează într-un fir și își schimbă starea
/// independent. La fiecare schimbare, își anunță observatorii.
{$ifdef fpc}{$mode delphi}{$H+}{$endif}
folosește SysUtils , Classes ;
tip
TBaseObserver = class ( TObject )
procedura Actualizare ( const stat : string ) ; virtual ; abstract ;
sfârşitul ;
TBaseSubject = procedura de clasă ( TObject )
AddObserver ( aobservator : TBaseObserver ) ; virtual ; abstract ; procedura RemoveObserver ( un observator : TBaseObserver ) ; virtual ; abstract ; procedura NotifyObservers ( const s : string ) ; virtual ; abstract ; sfârşitul ;
tip
{ Subiectul }
TSubject = clasă ( TBaseSubject )
fObservers private
: TList ; fSimulator : TStringList ; viteza : Integer ; procedură protejată Run ; constructor public Creare ; destructor Distruge ; suprascrie ; procedura AddObserver ( aobserver : TBaseObserver ) ; suprascrie ; procedura RemoveObserver ( un observator : TBaseObserver ) ; suprascrie ; procedura NotifyObservers ( const stat : string ) ; suprascrie ; procedura Go ; sfârşitul ;
TObserver = clasa ( TBaseObserver )
fname privat
: șir ; fsubject : TBaseSubject ; fstate : șir _ fgap : șir _ constructor public Creare ( asubject : TBaseSubject ; const aname , agap : string ) ; procedura Actualizare ( const stat : string ) ; suprascrie ; sfârşitul ;
{ Subiectul }
procedura TSubiect . alerga ;
var
i : întreg ;
s : șir _
începe
pentru i := 0 la fSimulator . Count - 1 do begin
s := fSimulator [ i ] ;
Writeln ( 'Subiect: ' , s ) ;
NotifyObservers ( i ) ;
Somn ( viteză ) ; //
sfârşitul milisecundelor ;
sfârşitul ;
constructor TSubject . a crea ;
începe
moștenit Creare ;
fObservers := TList . a crea ;
viteza := 200 ;
fSimulator := TStringList . a crea ;
fSimulator . AddStrings ([ '5' , '3' , '1' , '6' , '7' ]) ;
sfârşitul ;
destructor TSubiect . Distruge ;
începe
fObservatori . Gratuit ;
fSimulator . Gratuit ;
sfârşitul ;
procedura TSubiect . AddObserver ( un observator : TBaseObserver ) ; începe fObservatori . Adăugați ( un observator ) ; sfârşitul ;
procedura TSubiect . RemoveObserver ( un observator : TBaseObserver ) ; începe fObservatori . Eliminați ( un observator ) ; sfârşitul ;
procedura TSubiect . NotifyObservers ( const stat : string ) ;
var
i : întreg ;
începe
pentru i := 0 la fObservers . Count - 1 do
TBaseObserver ( fObservers [ i ] ) . Actualizare ( statut ) ;
sfârşitul ;
tip
{ TMethodThread }
TMethodThread = clasă ( TThread )
protejat
fMethod : TThreadMethod ;
procedura Execut ; suprascrie ;
constructor public
Creare ( AMethod : TThreadMethod ) ; sfârşitul ;
{ TMethodThread }
constructor TMethodThread . Creare ( AMethod : TThreadMethod ) ;
începe
fMetodă := AMetodă ;
FreeOnTerminate := Adevărat ;
moştenit Creare ( fals ) ;
sfârşitul ;
procedura TMethodThread . Execută ;
începe
dacă este atribuit ( fMethod ) apoi fMethod () ;
sfârşitul ;
procedura TSubiect . du-te ;
începe
TMethodThread . Creați ( Self.Run ) ; _ _ sfârşitul ;
constructor TObserver . Creare ( asubiect : TBaseSubject ; const aname , agap : string ) ;
începe
moștenit Creare ;
fsubiect := asubiect ;
fname := aname ;
fgap := agap ;
dacă este atribuit ( fsubject ) atunci fsubject . AddObserver ( auto ) ;
sfârşitul ;
procedura TObserver . Actualizare ( const stat : string ) ;
begin
fstate := stat ;
writeln ( fgap , fname , ': ' , stat ) ;
sfârşitul ;
/// Programul principal
var
subiect : TSubiect ;
observator : TObserver ;
observator2 : TObserver ;
beginsubject
: = TSubiect . a crea ; observator := TObserver . Creați ( subiect , „Centru” , #9#9 ) ; observator2 := TObserver . Creați ( subiect , „Dreapta” , #9#9#9#9 ) ; incearca subiectul . mergi () ; // Așteptați utilizatorul readln ; în sfârşit observator . Gratuit ; observator2 . Gratuit ; subiect . Gratuit ; sfârşitul ; sfârşitul .
Cod sursă Ruby
module Observable
def initialize
@observers = []
end
def add_observer ( observator )
@observers << observator cu excepția cazului în care @observers . include? ( observator )
sfârşit
def delete_observer ( observator )
@observers . şterge ( observator )
sfârşit
def notify_observers
@observers . fiecare { | x | x . update ( self )}
sfârşit
sfârşit
Clasa Angajat
include Observable
attr_reader :nume
attr_accessor :title , :salary
def initialize ( nume , titlu , salariu )
super (
) @nume = nume
@titlu = titlu
@salariu = sfarsitul salariului
class BaseObserver
def update
raise „Trebuie să implementeze funcția „actualizare””
end
end
class Salarizare < BaseObserver
def update ( angajat )
p ( „Tăiați un nou cec pentru #{ angajat . nume } !” )
p ( „Salariul lui este acum #{ angajat . salariu } !” )
end
end
class TaxMan < BaseObserver
def update ( angajat )
p ( „Trimite #{ angajat . nume } o nouă factură fiscală!” )
end
end
mike = Angajat . nou ( „Mike” , „proiect manager” , 25000 )
mike . add_observer ( Salarizare . nou )
mike . add_observer ( TaxMan . nou )
mike . salariu = 35000
mike . title = 'senior project manager'
mike . notify_observers
=begin
Rezultatul
„Tăiați un nou cec pentru Mike!”
"Salariu lui este acum 35000!"
„Trimite-i lui Mike o nouă factură fiscală!”
=sfarsit
Cod sursă în Rust
/// Exemplul descrie cum să primiți date de la o stație meteo (structură WeatherData, dispecer de evenimente) și
/// folosiți-l pentru a le afișa pe ecran (structura CurrentConditionsDisplay, ascultător de evenimente).
/// Ascultătorul este înregistrat cu observatorul folosind metoda register_observer, care are o închidere și
/// îl adaugă la lista de observatori. Când datele meteo se modifică, este apelată metoda notify_observers, care închide
/// toți ascultătorii, transmițându-le datele actualizate.
utilizați std ::
rc ::
Rc ;
utilizați std ::
cell ::
RefCell ;
tip ObserverFn = Box < dyn Fn ( f32 , f32 , i32 ) > ;
trăsătură observabilă {
fn register_observer ( & mut self , o :
ObserverFn ) ->
usize ;
fn remove_observer ( & mut self , idx :
use );
fn notify_observers ( & mut self );
}
#[deriva (implicit)]
struct WeatherData {
observatori :
Vec < ObserverFn > ,
temperatura :
f32 ,
umiditate :
f32 ,
presiune :
i32 ,
}
impl WeatherData {
fn set_measurements ( & mut self , temperatura :
f32 , umiditate :
f32 , presiune :
i32 ) {
sine . temperatura = temperatura ;
sine . umiditate = umiditate ;
sine . presiune = presiune ;
sine . notify_observers ();
}
}
impl Observabil pentru WeatherData {
fn register_observer ( & mut self , o :
ObserverFn ) ->
use {
sine . observatori . împinge ( o );
sine . observatori . len () - 1
}
fn remove_observer ( & mut self , idx :
usize ) {
sine . observatori . elimina ( idx );
}
fn notify_observers ( & mut self ) {
pentru observator în sine . observatori . iter () {
( * observator )( auto . temperatură , sine . umiditate , auto . presiune );
}
}
}
#[deriva (implicit)]
struct CurrentConditionsDisplay {
temperatura :
f32 ,
umiditate :
f32 ,
presiune :
i32 ,
}
impl CurrentConditionsDisplay {
fn display ( & self ) {
println! ( "Acum valorile sunt: {:.1} grade Celsius și {:.1} % umiditate. Presiune {} mmHg." ,
sine . temperatura , sine . umiditate , sine . presiune );
}
actualizare fn ( & mut self , temperatura :
f32 , umiditate :
f32 , presiune :
i32 ) {
sine . temperatura = temperatura ;
sine . umiditate = umiditate ;
sine . presiune = presiune ;
sine . afișaj ();
}
}
fn principal () {
let mut weather_data = WeatherData ::
implicit ();
let current_display = Rc ::
new ( RefCell ::
new ( CurrentConditionsDisplay ::
implicit ()));
fie observator = curent_afișare . clona ();
meteo_date . register_observer ( Box ::
new ( mutare | t , h , p | observator . borrow_mut (). update ( t , h , p )));
meteo_date . set_measurements ( 29,0 , 65,0 , 745 );
meteo_date . set_measurements ( 39,0 , 70,0 , 760 );
meteo_date . set_measurements ( 42,0 , 72,0 , 763 );
}
io
Io cod sursă
# Un exemplu este complet identic cu cel de mai sus în Python
Observator := Clona obiect
Observabil := Listă clona do (
registrează := getSlot ( "push" )
notify := metodă ( mesaj , self foreach ( observator , actualizare observator ( mesaj ))) ) Ziar := Clonă observabilă do ( addNews := metodă ( știri , notifica ( știri )))
Citizen := Observer clone do (
create := metoda ( nume , autoclonare lexicalDo ( nume := nume )) update := metoda ( mesaj , writeln ( nume .. " a aflat: " .. mesaj )) )
ziar := Clonă de ziar
ziar do (
înregistrați ( Citizen create ( „Ivan” ) ))
register ( Citizen create ( „Vasily” ))
addNews ( „Observer - Behavioral Design Pattern” )
)
#>>>> Ivan a învățat următoarele: Observatorul este un model de design comportamental
#>>>> Vasily a învățat următoarele: Observatorul este un model de design comportamental
Text sursă în javascript
class Observable {
constructor () {
this . ascultători = {};
}
// Abonati-va.
on ( e , callback ) {
if ( this . listeners [ e ] == nedefinit ) {
this . ascultători [ e ] = {};
aceasta . ascultători [ e ]. eventProperty = {};
aceasta . ascultători [ e ]. eventProperty . isOnOnce = fals ;
aceasta . ascultători [ e ]. date = [];
}
aceasta . ascultători [ e ]. date . push ( callback );
}
// Abonați-vă o dată.
onOnce ( e , callback ) {
this . on ( e , callback );
aceasta . ascultători [ e ]. eventProperty . isOnOnce = adevărat ;
}
// Dezabonare.
off ( e , apel invers ) {
this . ascultători [ e ]. date = asta . ascultători [ e ]. date .
filtru ( function ( ascultător ) { return listener !== callback ; });
}
// Trimite mesaj către abonați.
emit ( e , date ) {
dacă ( acest . ascultători [ e ] == nedefinit || acest . ascultători [ e ]. date == nedefinit ) {
return ;
}
let itObj = this ;
aceasta . ascultători [ e ]. date . forEach ( listener => {
if ( itObj . listeners [ e ] eventProperty . isOnOnce ) {
itObj . off ( e , itObj . listeners [ e ]. data [ 0 ]);
}
listener ( data );
});
}
}
Informații suplimentare
În .NET Framework 4.0 , modelul de proiectare al observatorului este implementat prin implementarea interfețelor generice System.IObservable<T>și System.IObserver<T>[2] .
Literatură
- Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides . Tehnici de proiectare orientată pe obiecte. Design Patterns = Design Patterns. Elemente de software reutilizabil orientat pe obiecte. - Sankt Petersburg. : Peter, 2009. - 366 p. - ISBN 978-5-469-01136-1 .
- Eric Freeman, Elizabeth Freeman. Modele de design = Head First Design Patterns. - Sankt Petersburg. : Peter, 2011. - 656 p. - ISBN 978-5-459-00435-9 .
Note
- ↑ Modelul de observator . Consultat la 13 iunie 2013. Arhivat din original pe 13 iunie 2013. (nedefinit)
- ↑ 1 2 Model de proiectare Observer . Consultat la 13 iunie 2013. Arhivat din original pe 13 iunie 2013. (nedefinit)
- ↑ Modelul de observator . Preluat la 4 noiembrie 2019. Arhivat din original la 4 noiembrie 2019. (nedefinit)