2015 syksy 2. vsk VIII Suunnittelumallit Observer ja State
Sisältö 1. Johdanto käyttäytymismalleihin 2. Observer 3. State Suunnittelumallit Observer ja State 2
VIII.1 Johdanto käyttäytymismalleihin Päätarkoitus algoritmien toteuttaminen ja vastuiden jakaminen olioiden välillä Kuvaavat luokkien ja olioiden rakenteen lisäksi niiden välisen kommunikoinnin ilmenemismuodot Soveltuvat tapauksiin, joissa suorituspolku vaikea seurattava Mallit siirtävät huomion suorituspolusta olioiden välisiin suhteisiin Luokkamallit toteutetaan käyttäen hyväksi perintää Oliomalleissa käytetään koosteolioita Suunnittelumallit Observer ja State 3
VIII.2 Observer (Tarkkailija) Yleinen ongelma: Yhteistyötä tekevien luokkien rakenteessa syntyy kytkentöjä -> uudelleenkäyttö hankaloituu Malli vähentää kytkentöjä Tyypillinen tilanne: käyttöliittymän näkymät riippuvat samasta datasta mutta eivät tiedä toisistaan Keskeiset toimijat kohde (subject, observable) ja tarkkailijat (observers) Julkaise-tilaa-suhde (publish-subscribe) Tarkkailijat rekisteröityvät kohteeseen, kohde ilmoittaa näille muutoksistaan Suunnittelumallit Observer ja State 4
VIII.2.1 Tarkoitus ja sovellettavuus Tarkoitus Olioiden välille yksi-moneen riippuvuussuhde, jossa ensimmäisen muutoksesta automaattinen ilmoitus muille olioille. Oliot päivitetään ilmoitettaessa. Sovellettavuus Kytkentäisyyden vähentäminen Ohjelman olioista yhden muuttaminen aiheuttaa muutoksen oliojoukossa, jonka kokoa ei ennalta tunneta Olion muutoksen halutaan välittyvän joukolle olioita, joiden identiteettiä ei ennalta tiedetä Suunnittelumallit Observer ja State 5
VIII.2.2 Luokkakaavio Tarkkailtava olio, joka tuntee tarkkailijansa Rajapinta tarkkailijoille Sisältää tilan, jota tarkkaillaan Sisältää tilan, joka pidetään ConcreteSubjectia vastaavana Observer-mallin luokkarakenne. Vrt. Gamma, Helm, Johnson, Vlissides: Design Patterns: Elements of Reusable Object-Oriented Software, Addison-Wesley 1995 6
Useita näkymiä, automaattinen päivitys Javapohjainen esimerkki Observable Observer update() addobserver() removeobserver() notifyobservers() NumeroNakyma MittariNakyma KeliNakyma update() update() update() Saatieto lampotila : double annalampotila() -8 C 30 20 10 0-10 -20 LIUKASTA Lähde: Lasse Harjumaan luentokalvot 7
VIII.2.3 Periaatteellinen C++-toteutus // Tarkkailijoiden kantaluokka class Observer { public: virtual ~Observer(){}; virtual void update(subject* changedsubject) = 0; }; // Kohde-luokan määrittely class Subject { public: virtual ~Subject(){}; virtual void attach(observer*); virtual void detach(observer*); virtual void notify(); private: std::list<observer*> observers; }; Suunnittelumallit Observer ja State 8
VIII.2.3 Periaatteellinen C++-toteutus (2) // Kohde-luokan metodit void Subject::attach (Observer* o) { observers.push_back(o); } void Subject::detach (Observer* o) { observers.remove(o); } void Subject::notify () { std::list<observer*>::iterator iter; for (iter = observers.begin(); iter!= observers.end(); iter++) { (*iter)->update(this); } } Suunnittelumallit Observer ja State 9
VIII.2.3 Periaatteellinen C++-toteutus (3) // Varsinainen kohde-luokka class ConcreteSubject : public Subject { // Luokan koodia // Metodi joka aiheuttaa ilmoituksen tarkkailijoille public: void changestate(); }; void ConcreteSubject::changeState(){ // Muutos olion tilassa notify(); } Suunnittelumallit Observer ja State 10
VIII.2.3 Periaatteellinen C++-toteutus (4) // Varsinainen tarkkailijaluokka, perii myös jonkin // toiminnallisen luokan class ConcreteObserver : public SomeClass, public Observer { }; // Luokan koodia // Metodi, joka suoritetaan, kun saadaan ilmoitus public: void update(subject *changedsubject); void ConcreteObserver::Update(Subject *changedsubject){ // Kysytään parametriolion tila ja // tehdään tarvittavat operaatiot } Suunnittelumallit Observer ja State 11
VIII.2.4 Etuja ja haittoja Euja Kohteita ja tarkkailijoita voi muokata toisistaan riippumatta Tarkkailijoita voidaan lisätä tekemättä muutoksia kohteisiin tai muihin tarkkailijoihin Kohde tietää tarkkailijoista vain, että ne toteuttavat yhteisen yksinkertaisen rajapinnan Haittoja Ilmoittaminen ei kohdennettu (broadcast) Tarkkailijat eivät tiedä kohteen muuttamisen seurauksia Tarkkailijat eivät tunne kohteen muutoksen syytä Suunnittelumallit Observer ja State 12
VIII.2.5 Mallin toteuttamisesta Yleensä kohde säilyttää tarkkailijat jonkinlaisessa listassa Jos kohteita paljon ja tarkkailijoita vähän, voi käyttää assosiatiivista hakua (hashtaulukko) Kohde voi välittää viitteen itseensä ilmoituksessa Tarkkailija voi kysyä kohteen tilaa Notify-kutsun voi jättää kohteen asiakkaiden tehtäväksi Tehokkaampi mutta epävarmempi Kohteiden poisto suunniteltava huolellisesti Tarkkailijoille voi jäädä roikkuvia osoittimia Moniperintäisissä kielissä toteuttaminen helpompaa Suunnittelumallit Observer ja State 13
VIII.2.6 Observer-tuki Javassa Java tukee suoraan mallia: perusluokat luokkakirjastossa Observer-rajapinta yksi metodi: void update(observable o, Object arg) Kohteelle Observable-luokka, metodeja public void addobserver(observer o) public void deleteobserver(observer o) public void notifyobservers() public void notifyobservers(object arg) protected void setchanged() Kutsuttava ennen ilmoittamista protected void clearchanged() Kutsuttava ilmoittamisen jälkeen Suunnittelumallit Observer ja State 14
VIII.3 State Ongelma: Tehtävä luokka, jonka käyttäytyminen muuttuu attribuuttien arvojoukon mukaan Johtaa usein koodissa mutkikkaisiin valintarakenteisiin Ratkaisu: Eristetään olion tila erityisiin tilaolioihin, joista valitaan yksi käytettäväksi kussakin tilanteessa State-suunnittelumalli Esimerkki: Yhtä asiakasta kerrallaan palveleva palvelin. Tilat (jokaiselle voidaan tehdä oma tilaolio) Kuuntelee pyyntöjä (Listening) Suorittaa pyyntöä (Serving) On suljettu (Closed) Suunnittelumallit Observer ja State 15
Esimerkin tilakaavio Palvelinoliolla kolme osaoliota, jotka vastaavat yo. tiloja Yksi kerrallaan aktiivinen Palvelinluokassa kolme viestiä (metodia), jotka vaihtavat aktiivista tilaa yo. kaavion mukaan Suunnittelumallit Observer ja State 16
VIII.3.1 Tarkoitus ja sovellettavuus Tarkoitus Luoda olio, jonka käyttäytyminen muuttuu sen sisäisen tilan mukaan niin, että olio näyttää vaihtavan luokkaansa Sovellettavuus Olion tilasta riippuvaa käyttäytymistä on muutettava ajon aikaisesti Luokan koodissa hankalia valintarakenteita, joissa ohjataan toimintaa sen tilan mukaan. Voidaan poistaa siirtämällä toimintaa sopiviin osaolioihin Suunnittelumallit Observer ja State 17
VIII.3.2 Luokkarakenne Määrittelee asiakkaihin päin näkyvän rajapinnan Tilaluokkien (abstrakti) kantaluokka Luokat, jotka toteuttavat kaikki mahdolliset tilat State-mallin luokkarakenne. Vrt. Gamma, Helm, Johnson, Vlissides: Design Patterns: Elements of Reusable Object-Oriented Software, Addison-Wesley 1995 18
VIII.3.3 Etuja ja haittoja Etuja Uusia tiloja helppo lisätä tekemällä uusia tilaluokkia Tilamuutokset helppo havaita koodista -> koodista luettavampaa Tilaoliot voidaan jakaa, jos niillä itsellään ei ole sisäistä tilaa Haittoja Context-luokan toiminta hajautuu useampaan luokkaan Suunnittelumallit Observer ja State 19
VIII.3.4 Toteuttamisesta Kuka vaihtaa tilaa? Context-olio itse Keskitetty, kankea Tilaoliot Joustavampi Tilanmuutoslogiikan vaihtaminen helpompaa Uusien tilojen lisääminen helpompaa Context-olioon tehtävä ylimääräinen rajapinta tilan muuttamiseksi Tilaolioiden kytkentä voi kasvaa Suunnittelumallit Observer ja State 20
VIII.3.4 Toteuttamisesta (2) Millä tavoin tilaoliot luodaan? Kaikki kerralla ja pidetään ohjelman suorituksen ajan Tilojen vaihtuessa tiuhaan parempi vaihtoehto Luodaan tarvittaessa ja hävitetään kun ei enää tarvita Kannattaa, kun tilaoliot suuria ja tilanvaihtoja harvoin Voidaan korvata taulukkoja käyttämällä Keskittyy enemmän tilasiirtymiin, State tilakohtaiseen käyttäytymiseen Suunnittelumallit Observer ja State 21