GoF projektavimo šablonai

Slides:



Advertisements
Similar presentations
ATVIRI VALDŽIOS DUOMENYS LIETUVOJE GALIMYBĖS VERSLUI, MOKSLUI IR VISUOMENEI Ūkio ministerija, diskusija-forumas
Advertisements

Software Engineering 1 Object-oriented Analysis and Design Applying UML and Patterns An Introduction to Object-oriented Analysis and Design and Iterative.
Chapter 26 GoF Design Patterns. The Adapter Design Pattern.
©Ian Sommerville 2000 Software Engineering, 6th edition. Chapter 20 Slide 1 Struktūrinis Testavimas.
1 Komponentai, kurie turi būti patikrinti, yra objektų klasės, kurios realizuojamos kaip objektai. l Didesniems vienetams negu individuali funkcija “baltos.
Tinklo samprata. Etaloniniai tinklo modeliai. OSI modelis
Moralinis gyvūnų* statusas Vakarų filosofijoje Parengė Linas Didvalis * Nors žmogus taip pat yra gyvūnas, tačiau aiškumo dėlei šiame.
Lietuvos vardo kilmė Žmogus, nepažįstantis savo tautos namų – Tėvynės žemės, kurioje nuo seno tėvai ir protėviai gyveno, - nėra savo krašto pilietis! Įsisąmoninkime.
Muzikos ženklų karuselė
NORĖDAMI PAKEISTI SKAIDRĖS STILIŲ – SPUSTELĖKIT E DEŠINIUOJU PELĖS KLAVIŠU ANT SKAIDRĖS FONO IR PASIRINKITE > LAYOUT ARBA DARBALAUKI O ĮRANKIŲ JUOSTOJE.
Vaizdinė užduotis. Kuriose iš šių valstybių galima pamatyti tokius gyvenamuosius namus? Jemene Tanzanijoje Mongolijoje Indonezijoje A B C D 1.
Duomenų struktūros KTU1 / 47 Kontrolinis – 2014 spalio d. Kontrolinis – tai teorinių žinių apie Java kalbos struktūras patikrinimas Bus vykdomas:
Klasės ir Objektai Javoje
Vartotojo sąsajos kūrimas, naudojant Java Swing biblioteką
Kaip parašyti testavimo planą?
Core Audio API Emilis Armonas.
SYSTEM OF PROGRAMMING BUDGET
Algoritmai ir duomenų struktūros (ADS)
Euronews Next
Smart none of us are as smart as all of us. smart none of us are as smart as all of us.
Medicininės radiologijos procedūrų pagrįstumas
Daugiakalbė naudotojo sąsaja (Multilingual User Interface)
Programinės įrangos prototipų naudojimas
Sistemos modeliai Rapid software development to validate requirements
Ekstremalus programavimas (XP)
Darbą parengė: Viktorija Drūteikaitė IT2
Robert Andruškevič AT27D.   Tai yra operacinė sistema, daugiausia naudojama išmaniuosiuose telefonuose, nors ją galima įdiegti ir kituose mobiliuosiuose.
GoF Design Patterns (Ch. 26). GoF Design Patterns Adapter Factory Singleton Strategy Composite Façade Observer (Publish-Subscribe)
Trigeriai 10 Paskaita.
Video kūrimas su Windows Movie Maker 2.0
Grafiniai interfeisai
Algoritmai ir duomenų struktūros (ADS)
Algoritmai ir duomenų struktūros (ADS)
PHP „CodeIgniter“ karkaso saugumas
Logika a.
R paketas ir jo įdiegimas
JavaScript kalbos apžvalga
Lekt. Tomas G. Lipnevičius
Windows API Tėvų kontrolė (angl. Parental Controls)
Įvadas į Java programavimo kalbą
Gijos (Threads) Java kalboje
Kas yra arduino ? Parengė:Karolis Šumskis ir Mokytoja ekspertė Elena Šišenina.
Atvirojo kodo elektronika
Programų sistemų inžinerija
Simple Network Management Protocol Paprastas tinklo valdymo protokolas
INTERAKTYVIŲ UŽDUOČIŲ KŪRIMO PROGRAMA
Paskirstytos atminties lygiagretusis programavimas Įvadas į MPI Distributed memory parallel programming.
Šlapimo nelaikymo korekcija: Vilniaus miesto Universitetinės ligoninės patirtis Dr. Gediminas Mečėjus I-ji Lietuvos uroginekologijos draugijos konferencija,
Antrosios kartos interneto technologijos
Windows Portable Devices
Windows Resource Protection (IŠTEKLIŲ APSAUGA)
3-4 klasei Matematika Trupmenos Jurgita Grajauskienė Spec
Studijos pristatymas 1DG Vadovas Algimantas Venčkauskas
Programų sistemų testavimas
Langų kūrimas.
Operacinė sistema Testas 9 klasė
Daugelio dokumentų sąsaja (angl. Multiple document interface)
Asmeninis programų kūrimo procesas (PSP)
Judrus projektų portfelio valdymas
Windows Ribbon Framework
Projektavimo šablonai (angl. design patterns)
Klasių diagramos Paskaitos tikslas – supažindinti su klasių diagramos notacija ir jos ryšiu su programiniu kodu.
Klaviatūra.
Grupinio darbo programinė įranga Lotus Notes
Kompiuterijos mokslo edukaciniai tyrimai
Pranešėjas Jurij Kuznecov
GoF Design Patterns (Ch. 26)
Presentation transcript:

GoF projektavimo šablonai Dviejų paskaitų tikslas – supažindinti su keletu GoF projektavimo šablonų ir jų taikymu POST

POST klasių diagrama su GoF projektavimo šablonais

Pirkimo proceso modeliavimas

Antra projekto iteracija realizuojant POST panaudos atvejus Realizuoti sąveiką su išorinėmis tarnybomis šių išorinių tarnybų interfeisai gali kisti! Realizuoti sudėtingesnes prekių kainos apskaičiavimo taisykles. Užtikrinti galimybę pasirinkti naujas biznio taisykles sistemos funkcionavimo metu. Kokybiškame objekiškai orientuotame projekte, minėtus uždavinius galima įgyvendinti tik naudojant projektavimo šablonus. Projekte paprastai naudojama daug vienas su kitu susijusių projektavimo šablonų.

Adapter Problema: kaip organizuoti vieningą veiklą esant nesuderinamiems interfeisams, t.y. kaip adaptuoti skirtingus interfeisus? Sprendimas: konvertuoti pradinį komponento interfeisą į kitą pavidalą tarpinio objekto-adapterio pagalba. Pavyzdžiui, projektuojama POST sistema turi bendradarbiauti su keliomis išorinėmis tarnybomis, turinčiomis skirtingus interfeisus (kurių pačių keisti mes negalime): mokesčių apskaičiavimo sistema, mokėjimų autorizavimo sistema atsiskaitant kreditine kortele, buchalterinės apskaitos sistema, sandėlio apskaitos sistema, ...

Adapter Kaip POST sistemai bendrauti su įvairiomis, pavyzdžiui, mokesčių apskaičiavimo sistemomis, kurių kiekis gali ateityje augti (o gal ir mažėti)? Bandant realizuoti su jomis ryšį tiesiogiai, gautume painų kodą su sudėtingomis loginėmis konstrukcijomis (spageti kodas), kurį atsiradus bet kokiems tarnybų pokyčiams, turėtume keisti. Problema sprendžiama, kiekvienai išorinei mokesčių apskaičiavimo sistemai sukuriant atskirą objekto-adapterio egzempliorių. POST pranešimai mokesčių apskaičiavimo sistemų adapteriams peradresuojami polimorfiškai. Naudojant Adapterio šabloną, objekto-adapterio klasės pavadinime būtinai turi būti naudojamas žodis Adapter. Tai palengvina diagramų ar kodo supratimą pašaliniams asmenims.

Pavyzdys: mokesčių apskaičiavimo sistema

Pavyzdys: mokesčių apskaičiavimo sistema Mokesčiams apskaičiuoti Sale kreipiasi (mokesciai()) į tuo metu naudojamą mokesčių apskaičiavimo sistemą, perduodama nuorodą į save kaip parametrą.

Klasių diagramos ir kodo ryšys Kuriant Register egzempliorių nurodoma naudojama mokesčių sistema. Tai atliekama inicijuojant bazinio tipo MokesciuSistemaAdapter nuorodą mokesciuSistemaAdapter reikiamu mokesčių sistemos adapterio, pavyzdžiui, MokesciuSistema1Adapter egzemplioriumi. Vykdant sisteminę operaciją pradetiNaujaPirkima() sukuriamas naujas prekių krepšelis ir jam perduodama nuoroda į naudojamą mokesčių sistemos adapterį. Mokesčiams apskaičiuoti prekių krepšelis turi specialų metodą mokesciai(). Šiame metode PrekiuKrepselis MokesciuSistemaAdapter metodu mokesciai() kreipiasi į tuo metu naudojamą mokesčių apskaičiavimo sistemą, perduodamas nuorodą į save kaip parametrą.

Klasių diagramos ir kodo ryšys Adapter šablono taikymas POST sistemoje Tai atliekama, pavyzdžiui, MokesciuSistema1Adapter egzemplioriuje randant tuo metu naudojamą mokesčių apskaičiavimo sistemą, pavyzdžiui, MokesciuSistema1 egzempliorių ir iškviečiant jo metodą mokesciai1(). Šiame metode iš prekių krepšelio paimamos visos jame esančios prekės, kiekvienai iš jų sukuriamas mokesčių MokamasMokestis egzempliorius ir įtraukiamas į grąžinamą mokamų mokesčių masyvą. Šiuo masyvu užpildomas atitinkamas mokamų mokesčių masyvas pačioje PrekiuKrepselis klasėje, taip sukuriant kompoziciją PrekiuKrepselis - MokamasMokestis. Pabaigoje, PrekiuKrepselis metode mokesciai() kiekvienos prekės mokesčiai sudedami ir bendra mokesčių suma grąžinama.

Factory Problema: kas turėtų sukurti objektą-adapterį? Kaip nustatyti, koks bus sukuriamo objekto-adapterio tipas, pavyzdžiui, TaxMasterAdapter ar GoodGoldTaxProAdapter? T.y. kurį kursime ir naudosime? Ir kaip kursime? Sprendžiant, turi būti atsižvelgta į fundamentalų projektavimo principą – skirtingų sistemos aspektų funkcionalumo atskyrimą, kurio esmė yra sistemos suskaidymas į modulius sutinkamai su skirtingais sistemos funkcionavimo aspektais ir uždaviniais. Pavyzdžiui, reikia atskirti dalykinės srities programinius objektus atsakingus tik už taikymo logikos realizavimą, atskirti objektų grupes atsakingas už saveiką su išorinėmis tarnybomis ir t.t...

Factory Su objekto-adapterio sukūrimu susijusių klausimų sprendimo negalima patikėti dalykinės srities objektui, nes tai nėra susiję su taikymo logika. Sprendimas: šiems tikslams turi būti naudojamas tarnybinis objektas. Factory šablonas skirtas kurti tarpusavyje susijusių klasių grupių objektus, kūrimo metu nenurodant konkrečių kuriamų objektų klasių. Naudojant Factory šabloną, minėto tarnybinio objekto klasės pavadinime būtinai turi būti naudojamas žodis Factory. Factory objektas (ServicesFactory) projektuojamas taip, kad, pavyzdžiui, naujų tipų adapteriai galėtų būti kuriami nemodifikuojant fabriko klasės. Tam tereikia pakeisti nustatytos savybės reikšmę ir užtikrinti naujos adapterio klasės pasiekiamumą.

Klasių diagramos ir kodo ryšys Užduotis: nustatyti norimos mokesčių sistemos adapterį, nurodant tik jos vardą - simbolių eilutę. Šiuo tikslu Register iškviečiamas PaslaugosFactory metodas gautiMokesciuSistemaAdapter(), kuriam per parametrus nurodomas, pavyzdžiui, klasės MokesciuSistema1Adapter vardas simbolių eilutės pavidale. Galimybė įvesti pasirenkamos mokesčių sistemos klasės vardą, vietoje išankstinio jos nurodymo programoje, žymiai padidina sistemos lankstumą.

Klasių diagramos ir kodo ryšys Metode gautiMokesciuSistemaAdapter() pagal nurodytą vardą randamas atitinkamos klasės failas, sukuriamas jos objektas o jo nuoroda grąžinama kaip metodo rezultatas. Nurodžius kitos mokesčių sistemos klasės vardą, būtų analogiškai grąžinama nuoroda į jos egzempliorių. Tokiu būdu, Factory šablono pagalba galime lanksčiai kurti objektus, šiuo atveju MokesciuSistemaAdapter, net jei jie nežinomi sistemos kompiliavimo metu.

Singleton Problema: o kas turi sukurti patį fabriko objektą ir kaip jį pasiekti? Fabriko gali prireikti įvairiems objektams, todėl, kad nekiltų nevienareikšmiškumų, fabriko objektas sistemoje iš principo turi būti tik vienas ir kreiptis į jį turi būti galima tik vienu būdu ir globaliai. Perdavimą fabriko per parametrus gali būti sunku realizuoti, kartais peikiamas globalus pasiekiamumas yra labai patogus. Sprendimas: Singleton šablonas, objekto, kuris turi būti vienintelis programoje atveju, siūlo naudoti statinį jo klasės metodą grąžinantį vienintelį tokį objektą: Naudojame statinį kintamąjį, kuris statiniame metode inicijuojamas Singleton objektu tik tuomet jei yra null.

Class.forName(Y).newInstance() Galime sukurti objektą be new sakinio, tiesiog iš baitkodų failo, nurodydami tik failo vardą Y.

Pavyzdys: buchalterinės apskaitos sistemos pasirinkimas getInstance() yra numanomas ir nevaizduojamas public class Register{ public void initialize(){ ServicesFactory.getInstance().getAccountingAdapter(); ... } Singleton objektas (šiuo atveju fabrikas) prieinamas metodu SingletonClass.getInstance(). Po to, jam galima perduoti pranešimą SingletonClass.getInstance().doFo() norimiems veiksmams atlikti (esantiems metode doFo()).

Pastabos Vienintelio egzemplioriaus sukūrimui paprastai naudojama pasyvi inicializacija (lazy initialization). Ji turi privalumų prieš aktyvią inicializaciją (eager initialization). Vienintelio egzemplioriaus kūrimo procesas (taigi ir kompiuterio resursų naudojimas) nepradedamas tol kol išties neprireikia kreiptis į šį egzempliorių. Inicializacijai kartais reikalinga gana sudėtinga logika. public class ServicesFactory{ private static ServicesFactory instance = new ServicesFactory(); public static ServicesFactory getInstance(){ return instance; } ...

Kodėl visus tarnybinius metodus nepadarius statiniais? Pavyzdžiui, gal ServicesFactory metodas getAccountAdapter galėtų būti statinis? Vienok, egzempliorių naudojimas turi savų privalumų: statiniai metodai nėra polimorfiniai (išskyrus programavimo kalboje SmallTalk), nutolusio iškvietimo mechanizmai (Java tai RMI) palaiko tik egzempliorių (t.y. nestatinius) metodus, egzempliorių panaudojimas yra lankstesnis: Singleton šablonas neleis, kad viename taikyme kokios tai klasės objektas būtų vienintelis, o kitame taikyme jau ne, Projektavimo pradžioje kartais atrodo, kad bus naudojamas tik vienas kokio tai objekto egzempliorius, o vėliau prireikia didesnio jų kiekio, taigi tenka modifikuoti praktiškai visą programą.

Factory ir Singleton šablonų taikymas POST sistemoje

Šablonų vardai ir idėjos leidžia abstrakčiau samprotauti ir aptarti projektinius sprendimus Projektuotojai bendrauja savo idėjas konkretizuodami šablonų pagalba. Pavyzdžiui: “skirtingų interfeisų sų išorinėmis tarnybomis problemą spęsime naudodami Adapter šabloną”; “resursų adapterius kursime šablonų Singleton ir Factory pagalba”...

Strategy Problema: kaip panaudoti skirtingus algoritmus, turint omenyje jų pasikeitimo galimybę? Pavyzdžiui, prėkės kaina gali priklausyti nuo sezoninių nuolaidų, nuolaidų pastoviems klientams ir t.t. Nuolaidų skaičiavimų taisyklės (algoritmai) gali keistis, pavyzdžiui: 10% nuo prėkės kainos, 10 Lt nuo kiekvienos prėkės brangesnės nei 200 Lt ir t.t. Sprendimas: kiekvienam algoritmui (politikai, strategijai) naudoti atskirą (strategijos) klasę (tai didina klasių skaičių sistemoje) su polimorfiniu metodu. strategijos objektas turi būti susiejamas su konteksto objektu (context object), kuriam ir taikomas algoritmas (strategija). Pastaba: Dėl strategijų skirtumų, vienų strategijų metodai gali turėti nereikalingų kitų strategijų metodams parametrų.

Pavyzdys: kainų politika Kiekvienam kainų apskaičiavimo algoritmui sukuriame savo strategijos klasę ...PricingStrategy, su polimorfiniu metodu getTotal. Konteksto objektas Sale, reikiamos nuolaidos apskaičiavimui iškviečia kurio tai strategijos objekto ...PricingStrategy metodą getTotal, perduodamas save patį parametru this. Strategijos objektas ...PricingStrategy metode getTotal naudoja konteksto objekto Sale nuorodą, kad galėtų iškviesti paties Sale metodą getPreDiscountTotal, grąžinantį bazinę prekių kainą, pagal kurią bus apskaičiuota reikiama nuolaida.

Strategijų klasės prekės kainos apskaičiavimui

Strategijos funkcionavimas Pasiuntus objektui Sale pranešimą getTotal, Sale deleguoja dalį savo užduočių strategijos objektui (nuolaidų apskaičiavimą). Pastebime, kad konteksto objektas Sale savo srategijos objektui PercentDiscountPricingStrategy užtikrina savo paties pasiekiamumą parametrų pagalba.

Sprendimas

Pastaba: objektas Sale turi nuorodą ne į konkrečią klasę, o į jos bazinį tipą, pavyzdžiui, interfeisą IPricingStrategy. Tokiu būdu, šios nuorodos pagalba galime prieiti prie bet kokio strategijos objekto, kurio klasė realizuoja šį interfeisą. Pastaba: Visoms strategijoms naudojamas vienodas interfeisas, nepriklausomai nuo to ar jie sudėtingi ar paprasti.

Klasių diagramos ir kodo ryšys Bazinės klasės KainuPolitikaStrategy pagalba galime pasirinkti reikiamą strategiją, pavyzdžiui, ProcentineKainuPolitikaStrategy arba SlenkstineKainuPolitikaStrategy egzempliorių. Prekių krepšelio kainai rasti, konteksto objekto PrekiuKrepselis metode gautiSuma() iškviečiamas, pavyzdžiui, ProcentineKainuPolitikaStrategy metodas gautiSuma(), perduodant save patį parametru this. Pastarąją aplinkybę vaizduojame klasių diagramoje priklausomybės ryšiu tarp konkrečių strategijų ir prekių krepšelio klasių.

Klasių diagramos ir kodo ryšys Strategijos, pavyzdžiui, ProcentineKainuPolitikaStrategy metode gautiSuma() naudojama konteksto objekto PrekiuKrepselis nuorodą, kad būtų galima iškviesti pačios PrekiuKrepselis klasės metodą gautiPradineSuma(), grąžinantį bazinę prekių kainą, pagal kurią bus apskaičiuota reikiama nuolaida. Kartu, šiame metode gautiPradineSuma() nustatomas PrekiuKrepselis egzemplioriaus atributas pradineSuma naudojamas PrekiuKrepselis metode gautiSuma(). Grąžinama ProcentineKainuPolitikaStrategy metodo gautiSuma() pinigų suma - nuolaida bus toliau naudojama (kaip viena iš dalių) galutinei pirkinio kainai rasti.

Strategy šablono taikymas POST sistemoje

Strategijos objekto sukūrimas Problema: kaip keisti kainų apskaičiavimo algoritmus? Objektiniame projektavime tai ekvivalentu klausimui “kas kurs konkrečių strategijų objektus?” Lanksčiam objektų kūrimui turime šabloną Factory. Analogiškai objektui ServicesFactory, turėsime objektą PricingStrategyFactory. Jam pakaks peduoti konkrečios srategijos klasės vardą ir kainų apskaičiavimo algoritmą bus galima keisti net programos darbo metu. Pastebime, kad kiekvienai objektų šeimai (išorinių tarnybų, kainų apskaičiavimo...) naudojamas atskiras Factory objektas.

Strategijos fabrikas Kaip ir dauguma fabrikų, PricingStrategyFactory turi būti vieninteliu tokiu egzemplioriumi su globaliu priėjimu, todėl jam taikome Singleton šabloną.

Strategijos objekto sukūrimas Sukūrus Sale egzempliorių jis kreipiasi į fabriką PricingStrategyFactory iš kurio gauna bazinio tipo, mūsų atveju, interfeiso IPricingStrategy nuorodą į konkretų strategijos objektą, mūsų atveju, PercentDiscountPricingStrategy (atitinkantį pasirinktą kainų apskaičiavimo algoritmą) kurį fabrikas ir sukuria.

Klasių diagramos ir kodo ryšys PrekiuKrepselis egzempliorius kreipiasi į fabriko KainuPolitikaStrategyFactory metodą gautiKainuPolitikaStrategy() iš kurio gauna bazinio tipo, mūsų atveju, abstrakčiosios klasės KainuPolitikaStrategy nuorodą į konkretų, fabriko sukurtą strategijos objektą, pavyzdžiui, ProcentineKainuPolitikaStrategy. Pažymėtina, kad tarp PrekiuKrepselis ir KainuPolitikaStrategyFactory klasių yra abipusiai priklausomybės ryšiai: PrekiuKrepselis naudoja statinius KainuPolitikaStrategyFactory metodus, o pastarosios klasės egzempliorius gauna PrekiuKrepselis egzempliorių per metodo gautiKainuPolitikaStrategy() parametrą.

Composite Problema: Užtikrinti galimybę vienu metu taikyti įvairų kiekį skirtingų strategijų. Pavyzdžiui, taikoma tokia kainų politika: 20% nuolaida garbės piliečiams, 15% nuolaida pastoviems pirkėjams perkantiems prekių daugiau nei už 400 Lt, pirmadieniais 50 Lt nuolaida perkant prekes už sumą virš 500 Lt, perkant vieną pakuotę arbatos Darjeeling, pirkėjas įgyja 15% nuolaidą visoms kitoms prekėms. Tarkime, garbės pilietis perka pakuotę arbatos Darjeeling ir kitų prekių už 600 Lt. Kaip apskaičiuoti jam tenkančią nuolaidą?

Pastabos apie kainų politiką Šio pavyzdžio strategijos skiriasi sekančiais faktoriais: laiku (pirmadienis...), pirkėjo tipu (garbės pilietis, pastovus pirkėjas...), pasirinkto produkto tipu (arbata Darjeeling) ir kiekiu... Šios problemos sprendimui parduotuvė suformuoja konfliktų sprendimo strategiją (conflict resolution strategy). Vienais atvejais gali būti naudojama didžiausios, kitais – mažiausios nuolaidos strategija. Taigi, vienu metu turime daug įvairių strategijų ir kiekvienam pirkėjui vienu metu gali būti taikomas skirtingas kiekis skirtingų strategijų. Kainų politikos taikymas priklauso nuo pirkėjo tipo, taigi, pirkėjo tipas turi būti žinomas objektui PricingStrategyFactory nuolaidos taikymo (konkrečios strategijos sukūrimo) perkamai prekei metu.

Composite taikymas Pastaba: Sale objektas neturi žinoti apie jam taikomų strategijų skaičių ir rūšis (nes jos pastoviai kinta ir jų kodas gali būti nežinomas), t.y. tai neturi būti jo klasės kode. Sprendimas: objektiniame projektavime sudėtingas elgesio būdas nustatomas kompozitinių ir paprastų objektų įdiegiančių tą patį interfeisą dariniu (objektu). Nuolaidos nustatymui jau turėjome interfeisą ISalePricingStrategy, tiktai dabar jame deklaruotas metodas getTotal turės grąžinti daugelio įvairiarūšių skaičiavimų rezultatą. Interfeisą ISalePricingStrategy, kaip ir anksčiau įdiegsime ne tik jau turėtais paprastais objektais-strategijomis PercentageDiscountPricingStrategy ir AbsoluteDiscountOverThresholdPricingStrategy, bei ir dar vienu kompozitiniu objektu-strategija CompositePricingStrategy.

Composite taikymas Kadangi nuolaidų strategijų gali būti įvairių, tai kompozitas CompositePricingStrategy bus viršklasė nuolaidos apskaičiavimo strategijų kompozitams, pvz.: CompositeBestForCustomerPricingStrategy ir CompositeBestForStorePricingStrategy. Galų gale, kompozitai-strategjjos yra sudaryti iš paprastų objektų-strategijų, kuriuos ir naudoja nuolaidos radimui. Pastebime, kad kompozitai turi (arba paveldi) atributą pricingStrategies, kuris yra nuoroda į visų ISalePricingStrategy objektų sąrašą. Tai skiriamasis kompozitinių objektų bruožas – išorinis kompozitas turi sąrašą vidinių objektų, lygiai taip pat pasiekiančių savo vidinius objektus, kaip ir išorinis kompozitas, ir t.t.

Composite taikymas Dabar su objektu Sale galima susieti kaip kompozitus, taip ir paprastus objektus objektui Sale tai atrodo kaip viena strategija, kadangi jam tai tiesiog objektas realizuojantis interfeisą ISalePricingStrategy ir “suprantantis” metodą getTotal(). Taigi, Sale gali naudoti bet kokį nuolaidų rinkinį, visai tuo “nesidomėdamas” ir nekeisdamas savo ryšio su nuolaidomis realizacijos. Pastaba: Composite šablono klasių objektams pasiekti yra naudojama rekursija.

Objektų sąveika pagal Composite šabloną

public abstract class CompositePricingStrategy implements ISalePricingStrategy{ protected List pricingStrategies = new ArrayList(); public add(ISalePricingStrategy s){ pricingStrategies.add(s); } public abstract Money getTotal(Sale sale);

public class CompositeBestForCustomerPricingStrategy extends CompositePricingStrategy { public Money getTotal(Sale sale){ Money lowestTotal=new Money(Integer.MAX_VALUE); for (Iterator i=pricingStrategies.iterator(); i.hasNext();){ ISalePricingStrategy strategy = (ISalePricingStrategy)i.next(); Money total = strategy.getTotal(sale); lowestTotal=total.min(lowestTotal); } return lowestTotal;

Kaip kurti strategijas? Pirmiausiai sukuriamas kompozitas (pvz.: palankiausias pirkėjui, ar parduotuvei), kurį savo ruožtu sudaro einamosios nuolaidų strategijos (jau paprastos), pavyzdžiui, PercentageDiscountPricingStrategy jei nuolaidų nėra, tai procentinė nuolaida bus 0% Jei toliau prireiks taikyti naują nuolaidų strategiją, ją bus lengva pridėti prie kompozitinio objekto iš CompositePricingStrategy paveldėtu metodu add. Skirsime du strategijų kūrimo laiko atžvilgiu variantus: nuolaida nustatoma kuriant Sale egzempliorių, nuolaida nustatoma įvedant į POST sistemą pirkėjo tipą.

1. Nuolaida nustatoma kuriant Sale egzempliorių strategijos klasės vardas gali būti įvedamas kaip sisteminė savybė, o procentinis nuolaidos dydis percent gali būti įvedamas JDBC pagalba.

2. Nuolaida nustatoma įvedant į POST sistemą pirkėjo tipą Šiuo atveju būtina dar viena (penkta) sisteminė operacija enterCustomerForDiscount, atliekama po sisteminės operacijos endSale. Naujos sisteminės operacijos argumentu turi būti pirkėjo identifikatorius customerID. Įvedamas iš kortelės ar klaviatūra. Strategijos klasės vardas, pavyzdžiui PercentageDiscountPricingStrategy, gali būti įvedamas kaip sisteminė savybė;

Nuolaidų strategijos sukūrimas konkrečiam pirkėjo tipui

Klasių diagramos ir kodo ryšys Register papildomas dar viena sistemine operacja ivestiKlientaNuolaidai(). Šiame metode, pagal per parametrus gautą kliento ID - simbolių eilutę pirkejasID nustatomas pirkėjas. Tuo tikslu kreipiamasi į klasės Parduotuve egzempliorių iškviečiant jo metodą gautiPirkejas(). Pastarasis metodas sukuria naują Pirkejas egzempliorių (turėtų sukurti pagal perduotą kliento ID). Pateiktame pavyzdyje sukuriamas "privelegijuotas" klientas.

Klasių diagramos ir kodo ryšys Pabaigoje Register metode ivestiKlientaNuolaidai() iškviečiamas klasės PrekiuKrepselis metodas ivestiKlientaNuolaidai(), kuriam per parametrus perduodamas gautas iš parduotuvės Pirkejas egzempliorius. PrekiuKrepselis egzempliorius savo metode ivestiKlientaNuolaidai() kreipiasi į fabriko KainuPolitikaStrategyFactory metodą gautiKainuPolitikaStrategy() iš kurio gauna bazinio tipo, mūsų atveju, abstrakčiosios klasės KainuPolitikaStrategy nuorodą (mūsų pavyzdyje) į strategijos kompozitą CompositePalankiausiaPirkejuiKainuPolitikaStrategy.

Klasių diagramos ir kodo ryšys Toliau pastajame KainuPolitikaStrategyFactory metode kainų politikos strategijos CompositeKainuPolitikaStrategy metodu add() konkrečių strategijų ProcentineKainuPolitikaStrategy ir SlenkstineKainuPolitikaStrategy egzemplioriai pridedami prie bazinės klasės KainuPolitikaStrategy kolekcijos saugančios KainuPolitikaStrategy egzempliorius. Pabaigoje nuoroda į kompozitą grąžinama prekių krepšeliui ir inicijuoja jo nuorodą kainuPolitikaStrategy.

Klasių diagramos ir kodo ryšys Dabar galutinei pirkinio sumai apskaičiuoti PrekiuKrepselis metode gautiSuma() per nuorodą kainuPolitikaStrategy bus iškviečiamas CompositePalankiausiaPirkejuiKainuPolitikaStrategy metodas gautiSuma(). Pastarajame metode bus perrinktos konkrečios strategijos, iškviesti jų metodai gautiSuma() ir pagal CompositePalankiausiaPirkejuiKainuPolitikaStrategy kainų politiką bus pasirinktas tinkamiausias konkrečios strategijos grąžinamas rezultatas.

Composite šablono taikymas POST sistemoje

Kodėl ne Register nurodo objektui PricingStrategyFactory sukurti naują strategiją ir neperduoda jos po to objektui Sale? Tai apsprendžia: šablonas Low Coupling Objektas Sale jau ir taip susietas su objektu-fabriku PricingStrategyFactory. Jei su objektu-fabriku būtų susietas ir Register, tai surištumas sistemoje išaugtų. šablonas Expert Objektas Sale yra ekspertas einamosios kainų politikos (jis ją taiko) klausimais (o ji gali keistis), todėl jam ir turi būti priskirta ši pareiga.

Pastaba: ID to Objects Identifikatorius customerID transformuojamas į objektą Customer, kai Register nurodo Store gauti pirkėją pagal jo identifikatorių. Store ši pareiga priskiriama pagal Expert šabloną. Šiam tikslui užklausą siunčia ne Sale, o Register, kadangi jis turi ryšį per atributą, be to priešingu atveju, Sale turėtų turėti nuorodą į Store, kas nepageidautina pagal Low Coupling šabloną. Objektiniame projektavime raktai ir identifikatoriai kaip taisyklė transformuojami į objektus. Toks sprendimas padidina sistemos lankstumą – pavyzdžiui Customer gali turėti papildomą informaciją apie pirkėją.

Pastaba: agregato perdavimas per parametrus Pranešimu addCustomerPricingStrategy, objektui-fabrikui per parametrus perduodamas objektas Sale ir tik po to objektas-fabrikas iš objekto Sale gauna objektus Customer ir PricingStrategy. Kodėl jie neperduodami atskirai vietoje Sale? Agregatą sudarantys objektai paprastai neišskiriami ir atskirai neperduodami: toks sprendimas paprastesnis, padidėja sistemos lankstumas, kadangi Sale gali valdyti šį informacijos perdavimo procesą.

Facade Problema: ką daryti su papildomomis biznio taisyklėmis, skirtomis sisteminių operacijų modifikavimui? Pavyzdžiui: Tarkime, yra galimi dovanų sertifikatai. Dažniausiai juo galima įsigyti tik vieną prekę. Tuomet visos operacijos enterItem, išskyrus pirmąją, turi būti atšaukiamos. Jei dovanų sertifikatu įsigyjant prekę kasininkas užklaustų apie grąžos skaičiavimą, tokia užklausa turėtų būti atšaukta. Tarkime, pirkinį galima apiforminti kaip parduotuvės labdaros akciją. Tokiose akcijose prekės kaina neturėtų viršyti, pavyzdžiui, 250 Lt, be to, pardavėju turėtų užsiregistruoti įgaliotas parduotuvės menedžeris.

Facade Papildomų biznio taisyklių realizavimas turėtų minimaliai paveikti jau esančius programinius komponentus. Sprendimas: sąveikai su sistema naudojame objektą-fasadą, pavyzdžiui, POSRuleEngineFacade užtikrinantį vieningą interfeisą ir atsakingą už sąveiką su sistemos komponentais; priežastis: programiniai komponentai paprastai turi labai įvairius interfeisus, todėl tiesioginė sąveika su jais nepageidautina. Pastebėsime, kad objekto-fasado kūrimui paprastai naudojamas Singleton šablonas.

Į objektą-fasadą kreipiamės prieš iškviesdami metodą, kurio veikimą norime modifikuoti. Pavyzdžiui, šiuo atveju, sprendžiama ar galima įsigyti dar vieną prekę. public class Sale{ public void makeLineItem(ProductSpecification spec, int quantity){ SalesLineItem sli=new SalesLineItem(spec,quantity); if(POSRuleEngineFacade.getInstance(). isInvalid(sli,this)) return; llineItems.add(sli); } ... Už fasado gali būti labai sudėtinga posistemė su daugybe objektų, ar gal ten aplamai ne objektinis kodas. Fasadas slepia visą posistemės realizacijos sudėtingumą.

<<priklausomybė>>

Klasių diagramos ir kodo ryšys PrekiuKrepselis metode ivestiPreke() patikriname ar gali būti parduodama prekė. Tam metodu gautiEgzempliorius() gaunamas vienintelis POSTaisyklesFacade egzempliorius, kuriam iškviečiamas jo metodas negalioja(). Pastarasis metodas nustato, ar pirkėjas yra privelegijuotas ir jei ne - grąžinama false. Pastaruoju atveju klasės PrekiuKrepselis metodas ivestiPreke() gali toliau tęsti savo veiklą, kurios tikslas yra įdėti prekę į krepšelį.

Klasių diagramos ir kodo ryšys Dar vienas patikrinimas - prekei "preke2", lengvata netaikoma. POSTaisyklesFacade metodas negalioja() grąžins true, visoms ne "preke2" parduodamoms prekėms. Taigi, išskyrus prekę "preke2", kitoms prekėms bus grąžinama false ir PrekiuKrepselis metodas ivestiPreke() galės toliau tęsti savo veiklą - įdėti tokias prekes į krepšelį.

Facade šablono taikymas POST sistemoje

Observer Problema: kaip atnaujinti GVS langą, pasikeitus pirkinio kainai? Kodėl pats Sale objektas (Subject) negalėtų pasiųsti atitinkamo pranešimo langui? Duomenų sluoksnio objektai neturi siųsti pranešimų GVS objektams – taip užtikrinamas silpnas jų surištumas, t.y. galima bus pakeisti GVS neliečiant biznio logikos ir atvirkščiai. Sprendimas: naudoti įvykių klausytojo interfeisą. Objektai klausytojai (Observer) realizuoja šį interfeisą ir dinamiškai registruojasi tokių įvykių klausytojais. Įvykus tokiam įvykiui, apie tai informuojami visi tokio įvykio klausytojai (per metodus kurių antraštės aprašytos ne Observer klasėje, o interfeise), dėka ko Observer objektai iškviečia Subject objektų metodus per Subject tipo nuorodą.

GVS lango atnaujinimas pasikeitus pirkinio kainai

Pavyzdys Aprašomas interfeisas PropertyListener su metodu onPropertyEvent. Aprašomas langas SaleFrame1 realizuojantis (susietas su interfeisu realizacijos ryšiu) šio interfeiso metodą onPropertyEvent. Inicijuojant langą SaleFrame1 jam perduodama nuoroda į Sale egzempliorių prie kurio registruosimės. Lango objektas SaleFrame1 registruojasi Sale egzemplioriaus įvykių klausytoju. Dabar pasikeitus pirkinio kainai langas bus apie tai informuojamas ir galės ją atvaizduoti. Pastebėsime, kad Sale objektas nesusijęs su GVS langu (taigi jį galima nepriklausomai keisti), jis susijęs tik su interfeisu PropertyListener. Objektas Sale apie pirkinio kainos pasikeitimus informuoja visus PropertyListener klausytojus (jei tokių yra).

Įvykių klausytojas SaleFrame1 registruojasi gauti informaciją apie objekto Sale savybių pasikeitimus

Pasikeitus Sale pirkinio kainai, ši informacija perduodama visiems tokių įvykių klausytojams pranešimu onPropertyEvent

SaleFrame1, realizuojantis interfeisą PropertyListener, realizuoja ir jo metodą onPropertyEvent. Gavęs šį pranešimą, jis savo ruožtu siunčia pranešimą JTextField egzemplioriui apie pirkinio kainos atnaujinimą.

Klasių diagramos ir kodo ryšys Pateikiamame pavyzdyje klasė Klientas atstovauja ne tik grafinę vartotojo sąsają, bet ir visą pirkimo procesą. Pastarasis yra modeliuojamas šios klasės metode klientoVeikla(). Observer šablono požiūriu svarbus yra kliento (Observer) prisiregistravimas prie prekių krepšelio (Subject). Tam iškviečiami klasės PrekiuKrepselis priregistravimo metodai priregistruotiTarpineSumaListener() ir priregistruotiGrazaListener(). Interfeisas TarpineSumaListener pateikia metodą tarpineSumaEvent() kurį iškviečia klasės PrekiuKrepselis metodas informuotiTarpineSumaListener(). Šis metodas informuoja visus aukščiau minėtus prisiregistravusius klausytojus (šiuo atveju klientą) įdiegiančius interfeisą TarpineSumaListener.

Klasių diagramos ir kodo ryšys Savo ruožtu šis metodas iškviečiamas kaskart įvedus naują prekę, t.y. kai Register objektas iškviečia PrekiuKrepselis metodą ivestiPreke() ir pirkimo pabaigoje, kai Register objekto metode pirkimoPabaiga() iškviečiamas PrekiuKrepselis metodas gautiSuma() galutinei pirkinio sumai pateikti. Analogiškai interfeisas GrazaListener aprašo metodo grazaEvent() antraštę, kurį iškviečia klasės PrekiuKrepselis metodas informuotiGrazaListener(). Šis metodas informuoja aukščiau minėtą prisiregistravusį klausytoją (šiuo atveju klientą) , įdiegiantį interfeisą GrazaListener. Savo ruožtu šis metodas yra iškviečiamas Register objekto metode uzmokestis(), kai reikia pateikti grąžos sumą, t.y. kai iškviečiamas klasės PrekiuKrepselis metodas uzmokestis().

Observer šablono taikymas POST sistemoje