Programavimas

Stebėtojo vidinis vaizdas

Ne taip seniai mano sankaba davė, todėl turėjau savo „Jeep“ tempti į vietinę atstovybę. Aš niekam nepažinojau atstovybės, ir nė vienas iš jų manęs nepažinojo, todėl daviau savo telefono numerį, kad jie galėtų man pranešti su sąmata. Šis susitarimas veikė taip gerai, kad mes atlikome tą patį, kai baigėme darbą. Kadangi visa tai man pasirodė puikiai, įtariu, kad atstovybės aptarnavimo skyrius naudoja tą patį modelį su dauguma savo klientų.

Šis skelbimo-prenumeratos modelis, kuriame yra stebėtojas registruojasi su a subjektas o vėliau gauna pranešimus, yra gana įprasta tiek kasdieniame gyvenime, tiek virtualiame programinės įrangos kūrimo pasaulyje. Tiesą sakant, Stebėtojas modelis, kaip žinoma, yra vienas iš objektinio programinės įrangos kūrimo pagrindinių elementų, nes jis leidžia bendrauti skirtingiems objektams. Šis gebėjimas leidžia jums prijungti objektus prie sistemos vykdymo metu, o tai leidžia labai lanksčią, išplečiamą ir daugkartinio naudojimo programinę įrangą.

Pastaba: Šio straipsnio šaltinio kodą galite atsisiųsti iš išteklių.

Stebėtojo modelis

Į Dizaino modeliai, autoriai stebėtojo modelį apibūdina taip:

Apibrėžkite priklausomybę tarp objektų nuo vieno iki daugelio, kad pasikeitus vieno objekto būsenai, visi jo priklausiniai būtų informuojami ir automatiškai atnaujinami.

Stebėtojo modelis turi vieną subjektą ir potencialiai daug stebėtojų. Stebėtojai registruojasi su subjektu, kuris praneša stebėtojams apie įvykius. Prototipinis stebėtojo pavyzdys yra grafinė vartotojo sąsaja (GUI), kuri vienu metu rodo du vieno modelio vaizdus; rodiniai registruojasi su modeliu, o pasikeitus modeliui, jie praneša rodiniams, kurie atitinkamai atnaujinami. Pažiūrėkime, kaip tai veikia.

Stebėtojai veikia

1 paveiksle pateiktoje programoje yra vienas modelis ir du vaizdai. Modelio verte, kuri atspindi vaizdo padidinimą, galima manipuliuoti judinant slankiklio rankenėlę. Rodiniai, „Swing“ vadinami komponentais, yra etiketė, rodanti modelio vertę, ir slinkties sritis, kuri keičia vaizdą pagal modelio vertę.

Programos modelis yra DefaultBoundedRangeModel (), kuris seka apribotą sveiko skaičiaus vertę - šiuo atveju nuo 0 į 100- taikydami šiuos metodus:

  • int getMaximum ()
  • int getMinimum ()
  • int getValue ()
  • boolean getValueIsAdjusting ()
  • int getExtent ()
  • void setMaximum (int)
  • void setMinimum (int)
  • void setValue (int)
  • void setValueIsAdjusting (loginė)
  • void setExtent (int)
  • void setRangeProperties (int reikšmė, int apimtis, int min, int max, loginės vertės koregavimas)
  • void addChangeListener (ChangeListener)
  • void removeChangeListener (ChangeListener)

Kaip rodo du paskutiniai aukščiau išvardyti metodai, DefaultBoundedRangeModel () palaikyti pokyčių klausytojus. 1 pavyzdyje parodyta, kaip programa naudojasi šia funkcija:

1 pavyzdys. Du stebėtojai reaguoja į modelio pokyčius

importuoti javax.swing. *; importuoti javax.swing.event. *; importuoti java.awt. *; importuoti java.awt.event. *; importuoti java.util. *; viešosios klasės testas pratęsia „JFrame“ { privatus „DefaultBoundedRangeModel“ modelis = naujas „DefaultBoundedRangeModel“ (100,0,0,100); privatus „JSlider“ slankiklis = naujas „JSlider“ (modelis); privatus „JLabel“ skaitymas = naujas „JLabel“ („100%“); privatus „ImageIcon“ vaizdas = naujas „ImageIcon“ („shortcake.jpg“); privatus ImageView imageView = naujas ImageView (vaizdas, modelis); viešasis testas () {super („Stebėtojo dizaino modelis“); Konteinerio contentPane = getContentPane (); JPanel skydas = naujas JPanel (); panel.add (nauja „JLabel“ („Nustatyti vaizdo dydį:“)); panel.add (slankiklis); panel.add (readOut); contentPane.add (skydelis, BorderLayout.NORTH); contentPane.add (imageView, BorderLayout.CENTER); model.addChangeListener (naujas „ReadOutSynchronizer“ ()); } public static void main (String args []) {Test test = new Test (); test.setBounds (100,100,400,350); testas. rodyti (); } klasės „ReadOutSynchronizer“ įgyvendina „ChangeListener“ {public void būsenaPakeista(„ChangeEvent e“) {String s = Integer.toString (model.getValue ()); readOut.setText (s + "%"); readOut.revalidate (); }}} klasės „ImageView“ praplečia JScrollPane {privatus JPanel skydelis = naujas JPanel (); privatus aspektas originalSize = naujas aspektas (); privatus Image originalImage; privati ​​„ImageIcon“ piktograma; public ImageView (piktograma „ImageIcon“, „BoundedRangeModel“ modelis) {panel.setLayout (naujas „BorderLayout“); panel.add (nauja „JLabel“ (piktograma)); this.icon = piktograma; this.originalImage = icon.getImage (); „setViewportView“ (skydelis); model.addChangeListener (naujas ModelListener ()); originalSize.width = icon.getIconWidth (); originalSize.height = icon.getIconHeight (); } klasės „ModelListener“ įgyvendina „ChangeListener“ {public void būsenaPakeista[ChangeEvent e] {BoundedRangeModel model = (BoundedRangeModel)e.getSource (); if (model.getValueIsAdjusting ()) {int min = model.getMinimum (), max = model.getMaximum (), span = max - min, value = model.getValue (); dvigubas daugiklis = (dviguba) reikšmė / (dviguba) trukmė; daugiklis = daugiklis == 0,0? 0,01: daugiklis; Vaizdo mastelis = originalImage.getScaledInstance ((int) (originalSize.width * daugiklis), (int) (originalSize.height * daugiklis), Image.SCALE_FAST); piktograma.setImage (pakeista); panel.revalidate (); panel.repaint (); }}}} 

Kai juda slankiklio rankenėlė, slankiklis keičia savo modelio vertę. Šis pakeitimas suaktyvina pranešimus apie įvykius dviem modelyje registruotiems pokyčių klausytojams, kurie koreguoja rodmenis ir keičia vaizdą. Abu klausytojai naudojasi pasikeitimo įvykiu, perduotu

stateChanged ()

norint nustatyti naują modelio vertę.

„Swing“ yra intensyvus „Observer“ modelio vartotojas - jis įgyvendina daugiau nei 50 įvykių klausytojų, kad įgyvendintų konkrečios programos elgseną - nuo reagavimo iki paspausto mygtuko iki lango uždarymo įvykio vetavimo vidiniam rėmui. Tačiau „Swing“ nėra vienintelis pagrindas, leidžiantis naudoti „Observer“ modelį - jis plačiai naudojamas „Java 2 SDK“; pavyzdžiui: „Abstract Window Toolkit“, „JavaBeans“ sistema, javax.naming paketą ir įvesties / išvesties tvarkytuvus.

1 pavyzdys konkrečiai parodo stebėtojo modelio naudojimą su „Swing“. Prieš aptardami daugiau „Observer“ modelio detalių, pažiūrėkime, kaip modelis paprastai įgyvendinamas.

Kaip veikia stebėtojo modelis

2 paveiksle parodyta, kaip yra stebėtojo modelio objektai.

Tiriamasis, kuris yra įvykių šaltinis, prižiūri stebėtojų kolekciją ir pateikia metodus, kaip pridėti ir pašalinti stebėtojus iš tos kolekcijos. Tiriamasis taip pat įgyvendina a pranešti () metodas, kuris praneša kiekvienam registruotam stebėtojui apie stebėtoją dominančius įvykius. Tiriamieji praneša stebėtojams, pasikviesdami stebėtoją atnaujinti () metodas.

3 paveiksle parodyta stebėtojo modelio sekos schema.

Paprastai kai kurie nesusiję objektai naudos subjekto metodą, kuris pakeis subjekto būseną. Kai taip atsitinka, subjektas kreipiasi į savo pranešti () metodas, kuris kartoja stebėtojų rinkimą, kviesdamas kiekvieną stebėtoją atnaujinti () metodas.

„Observer“ modelis yra vienas iš svarbiausių dizaino modelių, nes jis leidžia labai atsietiems objektams bendrauti. 1 pavyzdyje riboto diapazono modelis apie savo klausytojus žino tik tai, kad jie įgyvendina a stateChanged () metodas. Klausytojus domina tik modelio vertė, o ne tai, kaip modelis yra įgyvendinamas. Modelis ir jo klausytojai vieni apie kitus žino labai mažai, tačiau „Observer“ modelio dėka jie gali bendrauti. Šis didelis modelių ir klausytojų atsiejimo laipsnis leidžia kurti programinę įrangą, sudarytą iš prijungiamų objektų, todėl jūsų kodas yra labai lankstus ir daugkartinio naudojimo.

„Java 2 SDK“ ir „Observer“ modelis

„Java 2 SDK“ suteikia klasikinį „Observer“ modelio įgyvendinimą su Stebėtojas sąsaja ir Stebimas klasės iš java.util kataloge. Stebimas klasė atstovauja dalykui; stebėtojai įgyvendina Stebėtojas sąsaja. Įdomu tai, kad šis klasikinis „Observer“ modelio įgyvendinimas praktikoje naudojamas retai, nes tam reikia, kad dalykai išplėstų Stebimas klasė. Reikalavimas paveldėti šiuo atveju yra netinkamas dizainas, nes potencialiai bet kokio tipo objektai yra subjekto kandidatai ir todėl, kad „Java“ nepalaiko kelių paveldėjimų; dažnai tie dalykai kandidatai jau turi superklasę.

Stebėtojo modelio, kuris buvo naudojamas ankstesniame pavyzdyje, įgyvendinimas pagal įvykį yra didžiulis pasirinkimas, norint įdiegti stebėtojo modelį, nes tam nereikia, kad dalykai pratęstų tam tikrą klasę. Vietoj to, tiriamieji laikosi konvencijos, kuriai reikalingi šie viešojo klausytojo registravimo būdai:

  • anuliuoti addXXXListener (XXXListener)
  • negaliojantis pašalinimasXXXListener (XXXListener)

Kai tik tiriamasis surištą turtą (savybė, kurią pastebėjo klausytojai) pasikeičia, tiriamasis kartoja savo klausytojus ir naudoja metodą, „XXXListener“ sąsaja.

Iki šiol turėtumėte gerai suvokti stebėtojo modelį. Likusioje šio straipsnio dalyje daugiausia dėmesio skiriama kai kuriems „Observer“ modelio smulkesniems taškams.

Anoniminės vidinės klasės

1 pavyzdyje aš panaudojau vidines klases, kad įgyvendinčiau programos klausytojus, nes klausytojų klasės buvo glaudžiai susijusios su jų uždara klase; tačiau klausytojus galite įgyvendinti bet kokiu būdu. Vienas iš populiariausių pasirinkimų tvarkant vartotojo sąsajos įvykius yra anoniminė vidinė klasė, kuri yra klasė be pavadinimo, sukurta tiesiogiai, kaip parodyta 2 pavyzdyje:

2 pavyzdys. Įgyvendinkite stebėtojus su anoniminėmis vidinėmis klasėmis

... viešosios klasės testas pratęsia JFrame {... viešasis testas () {... model.addChangeListener (naujas ChangeListener () {public void stateChanged (ChangeEvent e) {String s = Integer.toString (model.getValue ()); readOut.setText (s + "%"); readOut.revalidate (); }}); } ...} klasės „ImageView“ išplečia JScrollPane {... viešoji „ImageView“ (galutinė „ImageIcon“ piktograma, „BoundedRangeModel“ modelis) {... model.addChangeListener (naujas ChangeListener () {public void stateChanged (ChangeEvent e) {BoundedRangeModel model = (BoundedRangeModel)e.getSource (); if (model.getValueIsAdjusting ()) {int min = model.getMinimum (), max = model.getMaximum (), span = max - min, value = model.getValue (); dvigubas daugiklis = (dviguba) reikšmė / (dviguba) trukmė; daugiklis = daugiklis == 0,0? 0,01: daugiklis; Vaizdo mastelis = originalImage.getScaledInstance ((int) (originalSize.width * daugiklis), (int) (originalSize.height * daugiklis), Image.SCALE_FAST); piktograma.setImage (pakeista); panel.revalidate (); }}}); }} 

2 pavyzdžio kodas yra funkciškai ekvivalentiškas 1 pavyzdžio kodui; tačiau aukščiau pateiktas kodas naudoja anonimines vidines klases, kad apibrėžtų klasę ir vienu ypu sukurtų egzempliorių.

„JavaBeans“ renginių tvarkytojas

Anoniminių vidinių klasių naudojimas, kaip parodyta ankstesniame pavyzdyje, buvo labai populiarus kūrėjų tarpe, todėl pradedant „Java 2 Platform“, „Standard Edition“ (J2SE) 1.4, „JavaBeans“ specifikacija prisiėmė atsakomybę už tų vidinių klasių diegimą ir kūrimą. „EventHandler“ klasė, kaip parodyta 3 pavyzdyje:

3 pavyzdys. „Java.beans.EventHandler“ naudojimas

importuoti java.beans.EventHandler; ... viešosios klasės testas pratęsia JFrame {... viešasis testas () {... model.addChangeListener (EventHandler.create (ChangeListener.class, this, "updateReadout")); } ... vieša niekinė updateReadout () {String s = Sveikasis skaičius į eilę (modelis.getValue ()); readOut.setText (s + "%"); readOut.revalidate (); }} ...