Ohjelmointi

Tarkkailija ja havaittavissa

Tässä on ongelma: Suunnittelet ohjelmaa, joka renderöi kolmiulotteisen kohtauksen kuvaavat tiedot kahdessa ulottuvuudessa. Ohjelman on oltava modulaarinen ja sen on sallittava useita samanaikaisia ​​näkymiä samasta kohtauksesta. Jokaisen näkymän on kyettävä näyttämään kohtaus eri näkökulmasta ja erilaisissa valaistusolosuhteissa. Vielä tärkeämpää on, että jos jokin osa taustalla olevasta kohtauksesta muuttuu, näkymien on päivitettävä itsensä.

Mikään näistä vaatimuksista ei ole ylitsepääsemätön ohjelmointihaaste. Jos jokaisen vaatimuksen käsittelevä koodi oli kirjoitettava de novose lisäisi kuitenkin merkittävää työtä kokonaisponnisteluihin. Onneksi Java-luokan kirjasto tarjoaa jo tukea näille tehtäville käyttöliittymän muodossa Tarkkailija ja luokka Havaittavissa- molemmat innoittivat osittain MVC-arkkitehtuurin vaatimukset.

Model / View / Controller (MVC) -arkkitehtuuri

Model / View / Controller -arkkitehtuuri esiteltiin osana Smalltalkia, Alan Kayn keksimää suosittua olio-ohjelmointikieliä. MVC on suunniteltu vähentämään järjestelmien rakentamiseen tarvittavaa ohjelmointityötä hyödyntämällä saman datan useita, synkronoituja esityksiä. Sen keskeisiä piirteitä ovat, että mallia, ohjaimia ja näkymiä kohdellaan erillisinä kokonaisuuksina ja että malliin tehdyt muutokset tulisi heijastaa automaattisesti jokaisessa näkymässä.

Edellä olevassa alkukappaleessa kuvatun ohjelmamallin lisäksi Model / View / Controller -arkkitehtuuria voidaan käyttää esimerkiksi seuraavissa projekteissa:

  • Kaaviopaketti, joka sisältää samanaikaisia ​​pylväsdiagrammi-, viivakaavio- ja ympyrädiagramminäkymiä samoista tiedoista.
  • CAD-järjestelmä, jossa suunnittelun osia voidaan tarkastella eri suurennuksilla, eri ikkunoissa ja eri mittakaavoissa.

Kuva 1 kuvaa MVC-arkkitehtuuria sen yleisimmässä muodossa. On yksi malli. Useat ohjaimet manipuloivat mallia; useat näkymät näyttävät mallin tiedot ja muuttuvat mallin tilan muuttuessa.

Kuva 1. Model / View / Controller -arkkitehtuuri

MVC: n edut

Model / View / Controller -arkkitehtuurilla on useita etuja:

  • Ohjelman komponenttien välillä on selkeästi määritelty ero - kunkin alueen ongelmat voidaan ratkaista itsenäisesti.
  • On hyvin määritelty sovellusliittymä - mikä tahansa, joka käyttää sovellusliittymää oikein, voi korvata joko mallin, näkymän tai ohjaimen.
  • Mallin ja näkymän välinen sitoutuminen on dynaamista - se tapahtuu ajo- eikä kääntöaikana.

Yhdistämällä MVC-arkkitehtuuri suunnitteluun, ohjelman osat voidaan suunnitella erikseen (ja suunnitella tekemään työnsä hyvin) ja sitoa sitten ajoaikaan. Jos komponentti katsotaan myöhemmin sopimattomaksi, se voidaan vaihtaa vaikuttamatta muihin kappaleisiin. Vertaa tätä skenaariota monoliittiseen lähestymistapaan, joka on tyypillistä monille nopeasti ja likaisille Java-ohjelmille. Usein kehys sisältää kaiken tilan, käsittelee kaikki tapahtumat, suorittaa kaikki laskelmat ja näyttää tuloksen. Siten kaikissa paitsi yksinkertaisimmissa tällaisissa järjestelmissä muutosten tekeminen tosiasian jälkeen ei ole triviaalia.

Osien määrittely

Malli on objekti, joka edustaa ohjelman tietoja. Se hallinnoi tietoja ja suorittaa kaikki muunnokset kyseisiin tietoihin. Mallilla ei ole tarkkaa tietoa sen ohjaajista tai näkemyksistä - se ei sisällä sisäisiä viittauksia kumpaakaan. Pikemminkin järjestelmä itse ottaa vastuun ylläpitää linkkejä mallin ja sen näkemysten välillä ja ilmoittaa näkemyksistä mallin muuttuessa.

Näkymä on objekti, joka hallitsee mallin edustaman datan visuaalista näyttöä. Se tuottaa malliesineen visuaalisen esityksen ja näyttää tiedot käyttäjälle. Se on vuorovaikutuksessa mallin kanssa viittaamalla itse mallikohteeseen.

Ohjain on esine, joka tarjoaa keinot käyttäjän vuorovaikutukseen mallin edustamien tietojen kanssa. Se tarjoaa keinot, joilla muutoksia tehdään joko mallin tietoihin tai näkymän ulkonäköön. Se on vuorovaikutuksessa mallin kanssa viittaamalla itse mallikohteeseen.

Tässä vaiheessa konkreettinen esimerkki voi olla hyödyllinen. Tarkastellaan esimerkkinä johdannossa kuvattua järjestelmää.

Kuva 2. Kolmiulotteinen visualisointijärjestelmä

Järjestelmän keskeinen osa on kolmiulotteisen kohtauksen malli. Malli on matemaattinen kuvaus kohtauksista muodostuvista kärjistä ja kasvoista. Kutakin kärkeä tai kasvoa kuvaavaa tietoa voidaan muokata (ehkä käyttäjän syötteen tai kohtauksen vääristymisen tai morfointialgoritmin seurauksena). Näkökulmasta, näyttötavasta (lankakehys tai kiinteä), perspektiivistä tai valonlähteestä ei kuitenkaan ole käsitystä. Malli on puhdas kuvaus elementeistä, jotka muodostavat kohtauksen.

Näkymä on ohjelman osa, joka muuntaa mallin tiedot graafiseksi näytöksi. Näkymä ilmentää kohtauksen todellisen näytön. Se on näkymän graafinen esitys tietystä näkökulmasta, tietyissä valaistusolosuhteissa.

Ohjain tietää, mitä mallille voidaan tehdä, ja toteuttaa käyttöliittymän, joka sallii kyseisen toiminnon aloittamisen. Tässä esimerkissä tietojen syöttämisen ohjauspaneeli saattaa antaa käyttäjän lisätä, muokata tai poistaa pisteitä ja kasvoja.

Tarkkailija ja havaittavissa

Java-kieli tukee MVC-arkkitehtuuria kahdella luokalla:

  • Tarkkailija: Mikä tahansa esine, joka haluaa ilmoituksen toisen objektin tilan muuttuessa.
  • Havaittavissa: Mikä tahansa esine, jonka tila voi olla kiinnostava ja johon toinen esine voi rekisteröidä kiinnostuksen.

Näitä kahta luokkaa voidaan käyttää toteuttamaan paljon enemmän kuin vain MVC-arkkitehtuuri. Ne soveltuvat mihin tahansa järjestelmään, jossa esineille on ilmoitettava automaattisesti muissa kohteissa tapahtuvista muutoksista.

Tyypillisesti malli on mallin alatyyppi Havaittavissa ja näkymä on Tarkkailija. Nämä kaksi luokkaa käsittelevät MVC: n automaattista ilmoitustoimintoa. Ne tarjoavat mekanismin, jolla näkymille voidaan ilmoittaa automaattisesti mallin muutoksista. Objektiviitteet malliin sekä ohjaimessa että näkymässä mahdollistavat pääsyn mallin tietoihin.

Tarkkailija ja havainnoitavat toiminnot

Seuraavassa on tarkkailijan koodiluettelot ja havaittavat toiminnot:

Tarkkailija

  • public void -päivitys (havaittava obs, Object obj)

    Soitetaan, kun havaittavissa olevassa tilassa on tapahtunut muutos.

Havaittavissa

  • public void addObserver (Observer obs)

    Lisää tarkkailijan sisäiseen tarkkailijoiden luetteloon.

  • public void deleteObserver (Observer obs)

    Poistaa tarkkailijan sisäisestä tarkkailijoiden luettelosta.

  • public void deleteObservers ()

    Poistaa kaikki tarkkailijat sisäisestä tarkkailijoiden luettelosta.

  • julkiset int-laskurit ()

    Palauttaa tarkkailijoiden lukumäärän sisäisessä tarkkailijaluettelossa.

  • suojattu void setChanged ()

    Asettaa sisäisen lipun, joka osoittaa, että havaittavissa oleva tila on muuttunut.

  • suojattu void clearChanged ()

    Tyhjentää sisäisen lipun, joka osoittaa, että havaittavissa oleva tila on muuttunut.

  • public boolean hasChanged ()

    Palauttaa loogisen arvon tosi, jos tämä havaittavissa oleva tila on muuttunut.

  • julkinen mitätön ilmoitusHavainnot ()

    Tarkistaa sisäisen lipun, onko havaittavissa oleva tila muuttunut, ja ilmoittaa siitä kaikille tarkkailijoille.

  • julkinen mitätön ilmoita havainnot (Object obj)

    Tarkistaa sisäisen lipun, onko havaittavissa oleva tila muuttunut, ja ilmoittaa siitä kaikille tarkkailijoille. Välittää parametriluettelossa määritetyn objektin ilmoittaa() tarkkailijan menetelmä.

Seuraavaksi tarkastelemme uuden luomista Havaittavissa ja Tarkkailija luokassa ja kuinka sitoa nämä kaksi toisiinsa.

Laajenna havaittavaa

Uusi luokan havaittavissa olevia esineitä luodaan laajentamalla luokkaa Havaittavissa. Koska luokka Havaittavissa jo toteuttaa kaikki tarvittavat menetelmät halutun käyttäytymisen aikaansaamiseksi, johdetun luokan on tarjottava vain jonkinlainen mekanismi havaittavan kohteen sisäisen tilan säätämiseksi ja käyttämiseksi.

vuonna ObservableValue Alla olevassa luettelossa mallin sisäinen tila kaapataan kokonaisluvulla n. Tähän arvoon pääsee (ja mikä tärkeintä, sitä muutetaan) vain julkisten käyttöoikeuksien kautta. Jos arvoa muutetaan, havaittavissa oleva objekti vetoaa omaansa setChanged () menetelmä osoittaa, että mallin tila on muuttunut. Sitten se vetoaa omiinsa ilmoitaHavainnot () menetelmällä kaikkien rekisteröityneiden tarkkailijoiden päivittämiseksi.

Listaus 1. ObservableValue

 tuoda java.util.havaittavissa; julkinen luokka ObservableValue ulottuu havaittavissa {private int n = 0; public ObservableValue (int n) {tämä.n = n; } public void setValue (int n) {tämä.n = n; setChanged (); ilmoitaHavainnot (); } public int getValue () {return n; }} 

Ota käyttöön tarkkailija

Uusi objektiluokka, joka tarkkailee toisen objektin tilan muutoksia, luodaan toteuttamalla Tarkkailija käyttöliittymä. Tarkkailija käyttöliittymä edellyttää, että päivittää() menetelmä tarjotaan uudessa luokassa. päivittää() -menetelmää kutsutaan aina, kun havaittavat muutokset ovat tilassa ja ilmoittaa tämän tosiasian kutsumalla sen ilmoitaHavainnot () menetelmä. Tarkkailijan tulisi sitten kuulustella havaittavaa kohdetta sen uuden tilan määrittämiseksi ja MVC-arkkitehtuurin tapauksessa säätää näkymänsä asianmukaisesti.

Seuraavassa TextObserver luettelo, ilmoittaa() menetelmä tarkistaa ensin, että päivityksen ilmoittanut havainnoitava on tarkkailijan tarkkailema. Jos se on, se lukee havaittavan tilan ja tulostaa uuden arvon.

Listaus 2. TextObserver

 tuo java.util.Observer; tuoda java.util.havaittavissa; public class TextObserver toteuttaa Observer {private ObservableValue ov = null; public TextObserver (ObservableValue ov) {this.ov = ov; } public void update (havaittava obs, Object obj) {if (obs == ov) {System.out.println (ov.getValue ()); }}} 

Sido nämä kaksi toisiinsa

Ohjelma ilmoittaa havaittavalle objektille, että tarkkailija haluaa saada ilmoituksen tilansa muutoksista kutsumalla havaittavan objektin addObserver () menetelmä. addObserver () menetelmä lisää tarkkailijan sisäiseen luetteloon tarkkailijoista, jotka tulisi ilmoittaa, jos havaittavan tila muuttuu.

Alla oleva esimerkki, joka näyttää luokan Main, osoittaa kuinka addObserver () - tapa lisätä TextObserver luokka (luettelo 2) seurattavaan luetteloon, jota ylläpitää ObservableValue luokka (Listaus 1).

Listaus 3. addObserver ()

 public class Main {public Main () {ObservableValue ov = new ObservableValue (0); TextObserver to = uusi TextObserver (ov); ov.addObserver (to); } public staattinen void main (String [] args) {Main m = new Main (); }} 

Kuinka kaikki toimii yhdessä

Seuraava tapahtumasarja kuvaa kuinka havaittavan ja tarkkailijan välinen vuorovaikutus tapahtuu tyypillisesti ohjelmassa.

  1. Ensin käyttäjä manipuloi ohjainta edustavaa käyttöliittymäkomponenttia. Ohjain tekee malliin muutoksen julkisen accessor-menetelmän kautta - mikä on aseta arvo() yllä olevassa esimerkissä.
  2. Julkisen käyttöoikeuden menetelmä muuttaa yksityisiä tietoja, säätää mallin sisäistä tilaa ja kutsuu sitä setChanged () menetelmä osoittamaan, että sen tila on muuttunut. Sitten se soittaa ilmoitaHavainnot () ilmoittaa tarkkailijoille, että se on muuttunut. Kutsu ilmoitaHavainnot () voidaan suorittaa myös muualla, kuten päivityssilmukassa, joka toimii toisessa säikeessä.
  3. päivittää() kutsutaan kutakin tarkkailijaa koskevia menetelmiä, mikä osoittaa, että tilassa on tapahtunut muutos. Tarkkailijat pääsevät mallin tietoihin mallin julkisten käyttömenetelmien kautta ja päivittävät näkemyksensä.

Tarkkailija / havaittavissa MVC-arkkitehtuurissa

Tarkastellaan nyt esimerkkiä, joka osoittaa, kuinka havaittavissa olevat ja tarkkailijat toimivat tyypillisesti yhdessä MVC-arkkitehtuurissa. Kuten mallissa ObservableValue (Listaus 1) Tämän esimerkin malli on hyvin yksinkertainen. Sen sisäinen tila koostuu yhdestä kokonaislukuarvosta. Tilaa manipuloidaan yksinomaan sisäänrakennetuilla menetelmillä ObservableValue. Mallin koodi löytyy täältä.

Aluksi kirjoitettiin yksinkertainen tekstinäkymä / ohjainluokka. Luokka yhdistää sekä näkymän (se näyttää tekstin mukaan mallin nykyisen tilan arvon) että ohjaimen ominaisuudet (sen avulla käyttäjä voi syöttää uuden arvon mallin tilalle). Koodi löytyy täältä.

Suunnittelemalla järjestelmä käyttämällä MVC-arkkitehtuuria (sen sijaan, että upotettaisiin mallin, näkymän ja tekstiohjaimen koodi yhteen monoliittiseen luokkaan), järjestelmä voidaan helposti suunnitella uudelleen käsittelemään toinen näkymä ja toinen ohjain. Tässä tapauksessa kirjoitettiin liukusäädin / ohjainluokka. Liukusäätimen sijainti edustaa mallin nykyisen tilan arvoa, ja käyttäjä voi säätää sitä asettamaan uuden arvon mallin tilalle. Koodi löytyy täältä.

Kirjailijasta

Todd Sundsted on kirjoittanut ohjelmia siitä lähtien, kun tietokoneita oli saatavana työpöydän malleina. Vaikka Todd oli alun perin kiinnostunut hajautettujen objektisovellusten rakentamisesta C ++: ssa, Todd muutti Java-ohjelmointikielelle, kun Java tuli itsestään selväksi valinnaksi sellaiselle.

Tämän tarinan "Observer and Observable" julkaisi alun perin JavaWorld.