Razširitev .Net Reactive razvijalcem ponuja nabor funkcij za implementacijo reaktivnega programskega modela za razvijalce .Net, da bi bilo ravnanje z dogodki enostavnejše in bolj izrazito z uporabo deklarativnih dejanj. Čeprav so ključni temelji reaktivnega skaliranja vmesniki IObserver in IObservable, kot razvijalec pogosto teh vmesnikov ni treba implementirati sam. Knjižnica podpira vgrajeni tip Subject<T>, ki implementira vmesnike in podpira številne funkcije.
Teme so osnova za različne teme, ki so na voljo v knjižnici, obstajajo pa tudi druge teme – ReplaySubject<T>, BehaviorSubject<T> in AsyncSubject<T>. Koristno je razumeti bistvene razlike med njima in kako jih uporabiti za boljšo rabo knjižnice.
V tem članku bomo primerjali<T> Subjekta in njegovega brata ter poskušali ponazoriti razlike v njunem vedenju.
Predmet<T>
Kot<T> je bilo že omenjeno, je Subject osnova za razpoložljive teme, saj omogoča enostaven način uporabe knjižnice brez potrebe po lastni implementaciji vmesnikov IObservable<T> in IObserver<T>. Spodaj je prikazan preprost prikaz vrste teme.
V zgornji kodi smo ustvarili <T>instanco Subject, in ker implementira<T> IObserver in IObserverable<T>, uporabimo isto instanco za naročnino in objavo vrednosti v IObserver. Še ena pomembna točka, ki jo je treba omeniti, je, kako uporabljamo preobremenitev metode Subscribe za sprejemanje dejanj kot vhoda. To se bo naredilo za vsako objavljeno vrednost, v tem primeru se številka natisne na konzolo.
Poskusimo prikazati objavljene vrednosti in vrednosti, ki jih IObserver (v tej akciji<T>) napiše na konzolo na naslednji sliki. To nam bo pomagalo enostavno primerjati preostale sorojence in različice.
Prva vrstica predstavlja objavljeno vrednost, druga vrstica pa vrednost, ki jo prejme IObserver. Poleg tega smo dodali vrstico, ki označuje, kdaj se opazovalec naroči na tok med izvajanjem. Ta črta je predstavljena z navpično pikčasto črto.
V zgornji kodi smo opazili, da se je opazovalec naročil na podatkovni tok pred objavo prve vrednosti. Slika prikazuje naročniško linijo, postavljeno pred prvi element. Kot lahko vidite iz izhodne linije, to trenutno nima vpliva na izhod.
Kaj pa, če se opazovalec naroči na podatke šele potem, ko so nekatere vrednosti že objavljene? Ali to vpliva na podatke, ki jih prejmejo opazovalci? Preden pogledamo izhod, najprej napišimo isto kodo.
V zgornji kodi lahko opazimo, da se opazovalec naroči na podatkovni tok šele po objavi dveh vrednosti (1 in 2). Kot bi pričakovali, bo to povzročilo, da opazovalci ne bodo prejeli objavljenih podatkov pred klicem metode naročnine. Kot je prikazano na spodnji sliki.
Kaj pa, če želite prebrati vse objavljene vrednosti, tudi če se opazovalec naroči pozno? Tu<T> pride v poštev ReplaySubject.
ReplaySubject<T>
ReplaySubject<T> shrani vrednosti in jih ponovno predvaja za kasnejše naročnike. To je koristno za izogibanje tekmovalnim razmeram. Spremenimo prejšnjo kodo, da uporabimo ReplaySubject<T> in poglejmo, kako to vpliva na to, kaj opazovalec prejme.
Kot je prikazano v zgornji kodi, v<T> <T>kodi skoraj ni sprememb, razen da zdaj uporabljamo ReplaySubject namesto subject. Naslednji diagram prikazuje vpliv na podatke, ki jih opazovalec prejme.
Kot je prikazano na sliki, se predpomnjena vrednost zdaj ponovno predvaja naročniku, tudi če se naročnik naroči kasneje. Seveda ima ta uporabna funkcija svojo ceno. Ta implementacija bo predpomnila vsako vrednost, ki jo objavi naročnik, kar lahko povzroči težave s slabim pomnilnikom, kadar je količina podatkov bistveno večja.
Vendar pa ima ReplaySubject<T> več kot en način za rešitev tega problema. Za namen tega primera si bomo ogledali dva primera, ki bosta uporabila omejitve velikosti in časa za omejitev predpomnjene vrednosti.
V prvem primeru bomo velikost predpomnilnika uporabili za omejitev vrednosti predpomnilnika. <T>Konstruktor ReplaySubject zagotavlja preobremenitev, ki sprejme celo število, ki predstavlja velikost predpomnilnika (največje število elementov). V našem primeru spremenimo kodo tako, da omejimo velikost predpomnilnika na 1.
Opazite, kako uporabljamo <T>preobremenitev konstruktorja ReplaySubject, da zagotovimo velikost predpomnilnika kot 1. To omejuje predpomnjenje in zagotavlja, da je predpomnjen le en element in zamenjan z novim elementom takoj, ko je objavljen. Vpliv spremembe je prikazan spodaj.
Drug način za omejitev predpomnjenja je omejitev časa predpomnjenega elementa oziroma določitev časa poteka za predpomnjenega elementa.
Napišimo kodo, da ponazorimo ta primer.
Podobno kot pri prejšnji kodi uporabljamo<T> preobremenitev konstruktorja ReplaySubject za določitev časa poteka elementov v predpomnilniku. Da bi dokazali naš primer, smo uvedli zamik med objavo vrednosti.
Ker traja polnih 1200 ms, da se opazovalec naroči, bodo vsi elementi, ki presežejo čas poteka 1000 ms, odstranjeni iz predpomnilnika. V tem primeru bo to povzročilo, da se vrednost 1 odstrani iz predpomnilnika in se ne bo ponovila za pozne naročnike. Kot je prikazano na spodnji sliki.
Obstajajo <T>tudi druge preobremenitve za ReplaySubject, ki omogočajo večjo prilagodljivost in natančno prilagajajo predpomnjene vrednosti, vendar bomo za primere ohranili že omenjena dva primera.
BehaviourSubject<T>
BehaviourSubject <T>je zelo podoben ReplaySubject<T>, saj pomaga pri vrednostih predpomnjenja. A obstaja pomembna razlika. BehaviourSubject<T> shrani le zadnjo objavljeno vrednost. Preden se poglobimo naprej, napišimo nekaj kode.
Če Vedenjski subjekt<T> predpomni le eno vrednost (ki je nazadnje znana), kako se razlikuje od ReplaySubjekta velikosti 1<T>? Naslednji diagram jasno odraža situacijo zgornje kode.
Vendar to ni povsem res. Tu sta dve pomembni razliki, ki jo je treba razumeti. Prvi je prisotnost neplačil. Upoštevajte, da v zgornji kodi <T>kot privzeto vrednost v konstruktorju BehaviourSubject navajamo vrednost 0. Če v predpomnilniku ni nobene vrednosti (ali z drugimi besedami, podatki niso bili objavljeni pred naročnino opazovalca), se privzeta vrednost vrne. To se razlikuje od ReplaySubject, ki ima velikost 1 <T>in nima nobene vrednosti. Naslednja koda in vizualna predstavitev zaporedja prikazujeta to vedenje.
Druga razlika je, kako se Vedenjski subjekt<T> in ReplaySubjekt<T> obnašata, ko se naročita na dokončano zaporedje. Ko se naročite po zaključku, BehaviorSubject <T> ne bo imel vrednosti, kot je prikazano v spodnji kodi.
Naročnikom je zagotovljeno, da ne bodo prejeli nobene vrednosti, saj naročnine potekajo po zaključku.
Vendar <T>pa je to primer pri ReplaySubject. Ni zagotovila, da opazovalec ne bo prejel nobenih vrednosti, kot je prikazano v spodnji kodi.
Kot je prikazano v zgornji kodi, je predpomnilnik velikosti 1 in tudi če je naročnina poklicana po zaključku klica, predpomnilnik ostane (dokler ni izpolnjen pogoj poteka), zato bo v tem primeru prejeta zadnja objavljena vrednost.
AsyncSubject<T>
AsyncSubject <T>je zadnji sorodnik Subjekta, ki ga bomo raziskali v tem članku<T>, in je zelo podoben prejšnjima dvema (ReplaySubject in BehaviourSubject), saj prav tako predpomni rezultate. A spet obstaja pomembna razlika. AsyncSubject objavi zadnjo predpomnjeno vrednost le, če je zaporedje označeno kot popolno <T> (predpomni le eno vrednost, zadnjo vrednost).
Razmislite o naslednji kodi.
To bo ustvarilo vrednost za opazovalca, da je zaporedje označeno kot zadnja vrednost, objavljena pred dokončanjem – vrednost 4. Kot je prikazano na spodnji sliki.
Kaj pa, če preskočimo klic, ki označi zaporedje kot dokončano? Komentirajmo vrstico in poskusimo znova.
To ne generira nobenih podatkov za opazovalca, ker AsyncSubject<T> objavi rezultate šele potem, ko je zaporedje označeno kot dokončano.
To je pomembna razlika, ki bi jo moral imeti v mislih vsak, ki uporablja AsyncSubject<T>.
Sklep
Ta članek prikazuje <T>razlike med različnimi sorojenci Subjekta in nekatere njegove različice. Pogosto je koristno biti pozoren na te subtilne razlike, saj lahko kažejo drugačno vedenje, kot ste pričakovali, če tega ne opazite.
Izvirna povezava:Prijava do hiperpovezave je vidna.
|