Vienas iš svarbiausių programinės įrangos kūrimo principų yra atviro ir uždaro dizaino principas. Šis projektavimo principas pabrėžia, kad klasės turi būti atviros pratęsimui, bet uždarytos modifikavimui. Dekoratoriaus dizaino modelis įkūnija atviro-uždaro dizaino principą.
Naudodami dekoratoriaus dizaino modelį galite lengvai išplėsti klasę, suteikdami jai naują elgesį, nekeisdami esamo kodo. Dekoratoriaus modelis tai daro dinamiškai vykdymo metu, naudodamas kompoziciją. Šis dizaino modelis žinomas kaip lanksti alternatyva paveldėjimo naudojimui, siekiant išplėsti elgesį.
Kaip veikia dekoratoriaus dizaino modelis?
Nors dekoratoriaus modelis yra alternatyva klasės palikimas, į savo dizainą įtraukiami kai kurie paveldėjimo aspektai. Pagrindinis dekoratoriaus modelio aspektas yra tai, kad visos jo klasės yra tiesiogiai arba netiesiogiai susijusios.
Įprastas dekoratoriaus dizaino modelis turi tokią struktūrą:
Iš aukščiau pateiktos klasių diagramos matote, kad dekoratoriaus modelis turi keturias pagrindines klases.
Komponentas: tai abstrakti klasė (arba sąsaja), kuri naudojama kaip dekoratoriaus modelio supertipas.
Betono komponentas: Tai yra objektai, kuriuos vykdymo metu galite papuošti skirtingais elgesiais. Jie paveldimi iš komponentų sąsajos ir įgyvendina abstrakčias jo funkcijas.
Dekoratorius: ši klasė yra abstrakti ir turi tą patį supertipą kaip ir objektas, kurį ji papuoš. Klasių diagramoje matysite du ryšius tarp komponentų ir dekoratorių klasių. Pirmieji santykiai yra paveldėjimo; kiekvienas dekoratorius yra komponentas. Antrasis santykis yra kompozicijos; kiekvienas dekoratorius turi (arba apvynioja) komponentą.
Betono dekoratorius: tai yra individualūs dekoratoriai, kurie komponentui suteikia specifinį elgesį. Turėtumėte atkreipti dėmesį, kad kiekvienas betono dekoratorius turi egzemplioriaus kintamąjį, kuriame yra nuoroda į komponentą.
Dekoratoriaus dizaino modelio įgyvendinimas Java
Picos užsakymo programos pavyzdys gali tinkamai parodyti, kaip naudoti dekoratoriaus modelį kuriant programas. Ši picų programa leidžia klientams užsisakyti picas su keliais priedais. Pirmoji dekoratoriaus modelio klasė yra picos sąsaja:
viešassąsajapica{
viešasabstrakčiai Styga apibūdinimas();
viešasabstrakčiaidvigubaikaina();
}
Picos sąsaja yra komponentų klasė. Taigi, iš jo galite sukurti vieną ar kelias konkrečias klases. Picų įmonė gamina dvi pagrindines picų rūšis pagal jų tešlą. Vienos rūšies pica turi mielinę tešlą:
viešasklasėYeastCrustPizzapadargaipica{
@Nepaisyti
viešas Styga apibūdinimas(){
grąžinti„Picos tešla su mielėmis“;
}
@Nepaisyti
viešasdvigubaikaina(){
grąžinti18.00;
}
}
YeastCrustPizza yra pirmasis betonas Java klasė „Pizza“ sąsajos. Kitas galimas picos tipas yra paplotėlis:
viešasklasėFlatbreadCrustPizzapadargaipica{
@Nepaisyti
viešas Styga apibūdinimas(){
grąžinti„Picos tešla iš paplotėlio“;
}
@Nepaisyti
viešasdvigubaikaina(){
grąžinti15.00;
}
}
FlatbreadCrustPizza klasė yra antrasis konkretus komponentas ir, kaip ir YeastCrustPizza klasė, įgyvendina visas abstrakčias Pizza sąsajos funkcijas.
Dekoratoriai
Dekoratorių klasė visada yra abstrakti, todėl negalite sukurti naujo egzemplioriaus tiesiai iš jos. Tačiau būtina užmegzti ryšį tarp skirtingų dekoratorių ir komponentų, kuriuos jie dekoruos.
viešasabstrakčiaiklasėTopping Dekoratoriuspadargaipica{
viešas Styga apibūdinimas(){
grąžinti"Nežinomas papildymas";
}
}
Klasė ToppingDecorator reiškia dekoratorių klasę šioje pavyzdinėje programoje. Dabar picų įmonė gali sukurti daugybę skirtingų užpilų (arba dekoratorių), naudodama „ToppingDecorator“ klasę. Tarkime, kad pica gali būti trijų skirtingų rūšių priedų, būtent sūrio, pipirų ir grybų.
Sūrio užpilas
viešasklasėSūristęsiasiTopping Dekoratorius{
privatus Pica pica;viešasSūris(Pica pica){
tai.pica = pica;
}@Nepaisyti
viešas Styga apibūdinimas(){
grąžinti pica.description() + ", Sūrio užpilas";
}
@Nepaisyti
viešasdvigubaikaina(){
grąžintipica.kaina() + 2.50;
}
}
Pepperoni užpilas
viešasklasėPepperonitęsiasiTopping Dekoratorius{
privatus Pica pica;viešasPepperoni(Pica pica){
tai.pica = pica;
}@Nepaisyti
viešas Styga apibūdinimas(){
grąžinti pica.description() + ", pipirų užpilas";
}
@Nepaisyti
viešasdvigubaikaina(){
grąžintipica.kaina() + 3.50;
}
}
Grybų užpilas
viešasklasėGrybastęsiasiTopping Dekoratorius{
privatus Pica pica;viešasGrybas(Pica pica){
tai.pica = pica;
}
@Nepaisyti
viešas Styga apibūdinimas(){
grąžinti pica.description() + ", grybų užpilas";
}
@Nepaisyti
viešasdvigubaikaina(){
grąžintipica.kaina() + 4.50;
}
}
Dabar turite paprastą programą, įdiegtą naudojant dekoratoriaus dizaino modelį. Jei klientas užsisakytų mielinę picą su sūriu ir pipirais, to scenarijaus bandymo kodas atrodys taip:
viešasklasėPagrindinis{
viešasstatinistuštumapagrindinis(String[] args){
Pica pica1 = naujas YeastCrustPizza();
pica1 = naujas Pepperoni (pica1);
pica1 = naujas Sūris (pica1);
System.out.println (pica1.description() + " $" + pica1.kaina());
}
}
Vykdant šį kodą konsolėje bus pateikta tokia išvestis:
Kaip matote, išvestyje nurodoma picos rūšis ir bendra kaina. Pica pradėta gaminti kaip mielinė pica už 18,00 USD, tačiau naudojant dekoravimo modelį, programa galėjo pridėti naujų funkcijų ir atitinkamos kainos picai. Taigi, picai suteikiamas naujas elgesys nekeičiant esamo kodo (mielių plutos pica).
Naudodami dekoratoriaus modelį taip pat galite taikyti tą patį objektą tiek kartų, kiek norite. Jei klientas užsisako picą su viskuo ir šiek tiek papildomo sūrio, galite atnaujinti pagrindinę klasę naudodami šį kodą, kad tai atspindėtų:
Pica pica2 = naujas YeastCrustPizza();
pica2 = naujas Pepperoni (pica2);
pica2 = naujas Sūris (pica2);
pica2 = naujas Sūris (pica2);
pica2 = naujas Grybai (pica2);System.out.println (pica2.description() + " $" + pica2.kaina());
Atnaujinta programa konsolėje pateiks šią išvestį:
Dekoratoriaus dizaino modelio naudojimo pranašumai
Du pagrindiniai dekoratoriaus dizaino modelio naudojimo pranašumai yra saugumas ir lankstumas. Dekoratoriaus modelis leidžia sukurti saugesnį kodą nesikišant į jau esamą saugų kodą. Vietoj to jis išplečia esamą kodą per kompoziciją. Veiksmingai užkertant kelią naujų klaidų atsiradimui ar nenumatytam šalutiniam poveikiui.
Dėl kompozicijos kūrėjas taip pat turi daug lankstumo naudodamas dekoratoriaus raštą. Bet kuriuo metu galite įdiegti naują dekoratorių, kad pridėtumėte naujos elgsenos nekeisdami esamo kodo ir netrukdydami programos.