parsisiųsti skaidrę
Download
Report
Transcript parsisiųsti skaidrę
Decorator
(Structural)
Decorator
Šablonas leidžia dinamiškai (programos
vykdymo metu) dekoruoti jau egzistuojančio
objekto elgseną.
Dekoruoti – panaudoti objekto gautus
rezultatus tolesniam jų apdorojimui kitais
skaičiavimais.
Lanksti ir dinaminė alternatyva statiniam
paveldimumo taikymui.
2
Realaus pasaulio pavyzdys
3
Motyvacija
Naudojant Decorator šabloną, išplečiamos ne
klasės, o tik atskiro jos egzemplioriaus
funkcionalumas.
Vien
paveldimumu tokio rezultato
pasiekti neįmanoma.
Šablonas leidžia išplėsti atskiro
egzemplioriaus funkcionalumą,
nemodifikuojant kitų jo klasės
egzempliorių.
4
Motyvacija
Dekoratoriaus (Wrapper) interfeisas yra toks pats,
kaip dekoruojamo objekto interfeisas.
Visi pranešimai, siunčiami pirminiam objektui, eina
per jį dekoruojančius dekoratorius.
Dekoratorius gali papildyti dekoruojamo objekto
funkcionalumą prieš pasiunčiant jam pranešimą arba
po to.
Dekoratorius galima keisti dinamiškai.
Objekto modifikavimas per paveldimumą yra
statinis ir atitinkama klasių hierarchija turi būti
žinoma iš anksto.
5
Motyvacija
Naudojant dekoratorius, galima išvengti
perteklinio klasių skaičiaus programoje.
Jei reikia praplėsti pirminio objekto
funkcionalumą keliolika būdų naudojant
paveldėjimą, gausis labai didelis klasių skaičius.
Paveldėjimo atveju visoms galimoms
funkcionalumo kombinacijoms turime kurti
atitinkamą klasę.
Dekoravimo atveju klases kuriame tik atskiroms
funkcionalumo dalims.
6
Motyvacija
Kadangi dekoratoriaus interfeisas yra
suderintas su jo dekoruojamo objekto
interfeisu, kreipiniai į šiuos abu objektus yra
identiški.
Tai leidžia lanksčiai, bet kokia tvarka
komponuoti dekoratorių objektus ir taip gauti
praktiškai neribojamas pirminio objekto
funkcionalumo modifikavimo galimybes.
7
Klasių diagrama
8
Struktūra
Component – abstrakti klasė (arba interfeisas),
nustatanti minimalų dekoratorių ir dekoruojamų
objektų bendravimo interfeisą.
Tai tą pačią antraštę turintys dekoratorių ir
dekoruojamų objektų metodai, kurių varde yra
žodis operation.
Abstrakčią klasę Component turi išplėsti ir
dekoruojamo (pirminio) objekto klasė
ConcreteComponent, ir dekoratorių klasių
hierarchijos bazinė klasė Decorator.
Per bendrą interfeisą galima vienu būdu apdoroti ir
konkrečius komponentus, ir dekoratorius, sujungiant
juos i grandinę.
9
Struktūra
Klasė Decorator turi nuorodą component į
abstrakčią klasę (interfeisą) Component, per
kurią galima pasiekti dekoruojamos klasės
egzempliorius.
Kūrimo metu nurodyta seka kiekvienas
konkretus dekoratorius priskiria nuorodą
component į toliau sekoje einantį konkretų
dekoratorių.
Savo ruožtu į jį patį įgyja nuorodą prieš jį
einantis sekoje konkretus dekoratorius.
10
Struktūra
Dekoratorių klasių hierarchijoje užklojamas
klasės Component metodas operation.
Konkretūs dekoratoriai per nuorodą
component gali pasiekti vieni kitus bei
konkretų komponentą ir taip keisti jo
funkcionalumą (panaudoti jo rezultatus savo
skaičiavimams).
Papildomą konkrečių dekoratorių
funkcionalumą diagramoje vaizduoja metodai
AddedBehavior.
11
Pavyzdys
12
Pavyzdžio objektų ir klasių
diagrama
13
Pavyzdys Nr.2
Vertically scrolling 2D space shooters have a spaceship
that:
Banks left or right, depending on motion
Typically have three animations:
Banking left, straight ahead, banking right
Also want to
Add particle effect for exhaust if the ship is
moving up the screen
But turn this off if it’s moving down the screen
Add a shield in front of the ship if the player picks up a shield
powerup.
Could accomplish all of these visuals using a series of
combined animations
Bank left, bank left and shield, bank left and
exhaust, bank left and shield and exhaust, etc..
But, leads to combinatoric expansion.
14
Decorating the spaceship with shield & exhaust
Instead of pre-defining all possible
animations…
Draw the shield, exhaust, and spaceship
separately
Can think of “decorating” the spaceship with a
shield, or an exhaust particle effect, as needed
No longer need large combinations of
animations
15
Some powerup options in Gradius
Gratuitous picture of a Vic Viper model
Decorators using object-oriented code
Basic idea is to create a linked list of objects
Each object draws one part of final scene…
E.g., the exhaust, the shield, etc.
… then calls the next object on the list
The final object is the main object being decorated
E.g., the spaceship
exhaust
shield
shield
spaceship
Exhaust, shield, and spaceship are object instances
spaceship
16
Realizacijos detalės
May need to know details about terminal object
Need to know position of spaceship to put shield directly in front,
and exhaust directly in back
Each object in list can be given reference to terminal object
Use reference to spaceship object to retrieve its current location
May need to remove a decorator
E.g., shields no longer active
Will need to write code that removes a decorator instance, and
repairs the links among remaining ones
If the removed decorator is the first in the chain, removal is easy
17
Pasekmės (+)
Didesnis lankstumas nei paveldėjimo atveju.
Su dekoratoriais atsakomybės gali būti pridėtos ar pašalintos
vykdymo metu.
Paveldėjimas reikalauja sukurti naują klasę, kiekvienai
naujai atsakomybei (pvz. BorderedScrollableTextView,
BorderedTextView). Tai padidina sistemos sudėtingumą.
Su dekoratoriais lengva pridėti tą pačią savybe kelis kartus (pvz.
dvigubas rėmelis).
Išvengiama įvairiomis savybėmis perkrautų klasių.
Galima apsibrėžti paprastą klasę ir papildyti jos
funkcionalumą dekoratorių pagalba.
Funkcionalumas gali būti sukomponuotas iš paprastų dalių.
To pasekoje taikomajai programai nereikia „mokėti“ už
savybes, kurių ji nenaudoja.
18
Pasekmės (-)
Dekoratorius ir jo komponentas nėra identiški.
Reikalingas sudėtingesnis situacijos
valdymas, kuomet reikia tiesioginio priėjimo
prie galutinio komponento.
Daug mažų objektų.
Naudojant šabloną, galutinė sistema dažnai
susideda iš didelio kiekio mažų objektų, kurie
yra panašūs.
Objektai skiriasi tik tuo, kaip jie yra sujungti, o
ne savo klasėmis ar kintamųjų reikšmėmis.
Tokias sistemas sunku derinti ir perprasti.
19
Pavyzdys Nr.3
Konkretus komponentas gali pakelti skaičių
kvadratu.
Dekoratoriai suteikia dvi papildomas
galimybes:
Padauginti konkretaus komponento gautą
rezultatą iš trijų;
Rasti jo natūrinį logaritmą.
20
Realizacija
Nuoroda, per kurią
dekoratoriai gali pasiekti ir
dekoruojamos klasės
ConcreteComponent
egzempliorius ir vieni kitus.
21
Rezultatas
component = CD1(CD1(CD2(component)
result*result
22
Rezultatas
Pagal šabloną dekoravus komponentą ,
klientui pakanka naudotis tik abstrakčiuoju
duomenų tipu (Component) ir taip išvengti
priklausomybės nuo konkrečių komponentų ir
dekoratorių klasių.
23
Command
(Behavioral)
24
Command
Šablonas siūlo komandoms ar jų grupėms
sukurti atitinkamą objektą.
Pasitelkiant šį objektą, komandas galima
saugoti, perduoti per parametrus, grąžinti
kaip ir bet kokį kitą objektą bei palaikyti
atšaukimo (undo) komandų seką.
25
Realaus pasaulio pavyzdys
26
Command kaip Macro
„Objektas, turintis simbolį, vardą ar raktą, kuris
reiškia komandų sąrašą, veiksmus ar klavišo
paspaudimus“.
Macro atvaizduoja komandą, kuri yra sudaryta iš
aibės apjungtų kitų komandų, nustatyta tvarka.
Command šablonas uždaro (encapsulates)
komandas (method calls) objektuose, tokiu būdu
leisdamas paskelbti užklausas nežinant
pageidaujamos operacijos ar objekto.
Šablonas suteikia galimybę sudaryti komandų eiles,
undo/redo veiksmus ir kitas manipuliacijas.
27
Motyvacija
Vartotojui sąveikaujant su taikymu, jo komandų
apdorojimo logika gali būti labai sudėtinga.
Bandymas numatyti visus galimus vartotojo
veiksmus ir sukurti tinkamai juos sąlygos sakiniais
interpretuojantį kodą gali būti ne tik
neįgyvendinamas, bet ir beprasmis.
Tokį kodą sunku modifikuoti keičiant vartotojo ir
taikymo sąveikos taisykles ar papildant jų sąveiką
naujomis komandomis.
Situacija taptų dar komplikuotesnė, jei
numatytume galimybę vartotojui atšaukti savo
veiksmus ar sujungti juos i makrokomandas.
28
Motyvacija
Norint gana lanksčiai manipuliuoti komandomis,
reikia jas „paversti“ objektais.
„Komandų objektų“ atvejis pasižymi tam tikra
specifika:
Iš anksto nėra žinoma, kokia komanda ir kokiam
objektui bus pateikta vienu ar kitu metu.
Šablonas suteikia galimybę dinamiškai parinkti
kiekvienai komandai reikiamą operaciją ir ją
atliekantį objektą.
Išsprendžiama dažna problema – atskiriami
pranešimo sukūrimo ir jo apdorojimo procesai.
29
Klasių diagrama
30
Struktūra
Command šablonas numatomoms operacijoms atlikti
naudoja Command (komandų) klasių hierarchiją.
Jos viršuje yra abstrakti klasė (interfeisas)
Command.
Ji turi abstraktų metodą execute.
Tai dinamiškai vykdomas komandų hierarchijos
metodas, kurį iškviečia klasės Invoker
egzempliorius (iškviečia komandą).
Šis metodas numatytiems komandos veiksmams
atlikti kreipiasi į klasės Receiver egzemliorių.
31
Struktūra
Klasė Receiver aprašo objektą, kurio
būseną keičia komandos.
Abstrakčią klasę Command išplečia klasės
ConcreteCommand.
Komandų hierarchijos egzemlioriai vadinami
konkrečiomis komandomis.
Kiekviena iš ConcreteCommand klasių turi
individualų metodo execute turinį, kuriame
aprašoma, kokie klasės Receiver metodai
yra iškviečiami konkrečioje komandoje.
32
Struktūra
Charakteringas šablono požymis – kliento klasėje sukuriami
ConcreteCommand egzemplioriai, kuriuos jis inicijuoja
atitinkamais klasės Receiver egzemlioriais.
Naudojant tokį jungtinį objektą – klasės ConcreteCommand
egzemliorių, gerokai supaprastėja komandų apdorojimo logika.
execute yra polimorfinis (užklojantysis) metodas, todėl visos
komandos traktuojamos vienodai.
Tai leidžia nesunkiai papildyti/pakeisti jų sąrašą.
Konkretų vykdomo metodo execute turinį sudaro iškviečiamos
klasės Receiver metodai.
Invoker egzemplioriuje gali būti iš anksto nežinoma nei kokia
konkreti operacija, nei su kokiu objektu ji bus atlikta.
Pranešimą galima parinkti, išsiųsti ir įvykdyti nepriklausomais laiko
momentais.
33
Sekų diagrama (1)
34
Sekų diagrama (2)
Klientas sukuria ConcreteComand objektą ir
specifikuoja juo gavėją (receiver).
Invoker objektas saugo ConcreteCommand.
Iškvietėjas (invoker) paleidžia užklausą
iškviesdamas Execute komandai.
Kuomet komandas galima anuliuoti (undo),
ConcreteCommand laiko būseną, esančią
prieš Execute iškvietimą.
ConcereteCommand objektas iškviečia
operacijas, užklausos apdorojimui.
35
Kada naudoti Command šabloną?
Reikalinga užklausų istorija.
Reikalingas undo (callback) funkcionalumas.
Užklausos turi būti apdorojamos skirtingais
laiko momentais ir skirtinga tvarka.
Iškvietėjas turi būti atskirtas nuo objekto,
apdorojančio iškvietimą.
36
Klasių diagrama
37
Pavyzdys
Padavėjas (Invoker) priima užsakymą iš kliento. Užsakymas
statomas į eilę ir patenka pas virėją, kur yra apdorojamas.
38
Dalyviai pavyzdyje
Client yra klientas:
Siunčia užklausą gavėjui (receiver) per padavėją
(Invoker).
Padavėjas uždaro (encapsulates) komandą
(užsakymą) užrašydamas ją ant čekio ir pateikia
virtuvei (sukuriamas ConcreteComand objektas,
kuris ir yra komanda).
Virėjas (Receiver), pabaigęs gaminti kitus
užsakymus, kurie jam buvo nusiusti prieš tai, pradeda
apdoroti gautą užsakymą.
39
Pasekmės
Šablonas atskiria objektą, kuris iškviečia
operaciją, nuo to objekto, kuris žino kaip ją
vykdyti.
Komandos yra pirminės klasės (first class)
objektai. Jomis galima manipuliuoti ir jas
praplėsti kaip bet kurį kitą objektą.
Galima sujungti komandas į vieną jungtinę
komandą.
Lengva pridėti naujas komandas, kadangi
nereikia keisti egzistuojančių klasių.
40
Pavyzdys
Receiver egzemlioriaus simbilių eilutės
kintamasis gali būti modifikuojamas dviem
komandomis:
Tarpų tarp žodžių pakeitimas žvaigždutėmis;
Mažųjų raidžių pakeitimas didžiosiomis.
41
Realizacija
42
Realizacija
Testo metu keliems klasės Receiver
egzemplioriams klientas sukuria kelias
konkrečias komandas jų būsenai modifikuoti.
Iškviečiant konkrečioms komandoms polimorfinį
metodą execute parodoma, kad Invoker
egzemlioriaus komandoms apdoroti galima
atsisakyti tradicines sąlygos sakinių logikos:
Bus vykdomas tos konkrečios komandos metodas
execute , kuriai tuo metu bus priskirta kliento
Command tipo nuoroda.
43
Rezultatas
Šablono pagalba galima sukurti konkrečias
komandas, manipuliuoti jomis kaip paprastais
objektais ir jas vykdyti naudojant tik komandų
hierarchijos interfeisą Command.
Atskyrę Invoker nuo jo naudojamų konkrečių
komandų klasių, sudarome prielaidas kurti aiškesnį,
lengvai plečiamą ir vystomą, komandų apdorojimui
skirtą kodą.
44
Pabaiga
45