A szoftverfejlesztés egyik legfontosabb alapelve a nyitott-zárt tervezési elv. Ez a tervezési elv hangsúlyozza, hogy az osztályoknak nyitottnak kell lenniük a bővítésre, de zártaknak kell lenniük a módosításra. A dekoratőr tervezési mintája a nyitott-zárt tervezési elvet testesíti meg.
A dekorátor tervezési mintájával egyszerűen kiterjesztheti az osztályt, új viselkedést biztosítva a meglévő kód megváltoztatása nélkül. A dekorátor minta ezt dinamikusan teszi futás közben, kompozíció segítségével. Ez a tervezési minta rugalmas alternatívája az öröklődés használatának a viselkedés kiterjesztésére.
Hogyan működik a lakberendező minta?
Bár a dekorátor minta alternatíva osztály öröklődés, az öröklődés bizonyos szempontjait beépíti a kialakításába. A lakberendező minta kulcsfontosságú szempontja, hogy minden osztálya közvetlenül vagy közvetve kapcsolatban áll egymással.
Egy tipikus lakberendező minta a következő szerkezettel rendelkezik:
A fenti osztálydiagramból látható, hogy a dekorátor mintának négy fő osztálya van.
Összetevő: ez egy absztrakt osztály (vagy interfész), amely a dekorátor minta szupertípusaként szolgál.
Betonkomponens: ezek azok az objektumok, amelyeket futás közben különféle viselkedésekkel díszíthet. Az összetevő interfésztől öröklik, és megvalósítják annak absztrakt függvényeit.
Dekoratőr: ez az osztály absztrakt, és ugyanaz a szupertípus, mint az objektum, amelyet díszíteni fog. Az osztálydiagramon két összefüggést fog látni a komponens és a dekorátor osztályok között. Az első kapcsolat az öröklődés; minden lakberendező egy összetevő. A második kapcsolat a kompozícióé; minden lakberendező van egy (vagy beburkol egy) komponenst.
Betondekorátor: ezek azok az egyedi dekorátorok, amelyek egy adott alkatrésznek sajátos viselkedést adnak. Megjegyzendő, hogy minden betondekorátornak van egy példányváltozója, amely hivatkozást tartalmaz egy összetevőre.
A Decorator Design Pattern implementálása Java nyelven
Egy minta pizzarendelési alkalmazás megfelelően bemutathatja, hogyan kell használni a dekorációs mintát alkalmazások fejlesztéséhez. Ez a minta pizza alkalmazás lehetővé teszi az ügyfelek számára, hogy rendeljenek pizzát több feltéttel. A dekorátor minta első osztálya a pizza felület:
nyilvánosfelületpizza{
nyilvánosabsztrakt Húr leírás();
nyilvánosabsztraktkettősköltség();
}
A Pizza felület az összetevő osztály. Tehát egy vagy több konkrét osztályt hozhat létre belőle. A pizzagyártó cég a tésztájuk alapján két fő pizzát készít. Az egyik pizzafajta élesztős tésztát tartalmaz:
nyilvánososztályYeastCrustPizzamegvalósítjapizza{
@Felülbírálás
nyilvános Húr leírás(){
Visszatérés"Pizza tészta élesztővel";
}
@Felülbírálás
nyilvánoskettősköltség(){
Visszatérés18.00;
}
}
A YeastCrustPizza az első beton Java osztály a Pizza felületről. A másik elérhető pizzafajta a laposkenyér:
nyilvánososztályFlatbreadCrustPizzamegvalósítjapizza{
@Felülbírálás
nyilvános Húr leírás(){
Visszatérés"Pizza tészta laposkenyérrel";
}
@Felülbírálás
nyilvánoskettősköltség(){
Visszatérés15.00;
}
}
A FlatbreadCrustPizza osztály a második konkrét komponens, és a YeastCrustPizza osztályhoz hasonlóan megvalósítja a Pizza felület összes absztrakt funkcióját.
A dekorátorok
A dekoratőr osztály mindig absztrakt, ezért nem hozhat létre közvetlenül belőle új példányt. De szükséges kapcsolatot teremteni a különböző dekorátorok és az általuk díszített alkatrészek között.
nyilvánosabsztraktosztályTopping Dekorátormegvalósítjapizza{
nyilvános Húr leírás(){
Visszatérés"Ismeretlen öntet";
}
}
A ToppingDecorator osztály a dekorátor osztályt képviseli ebben a példaalkalmazásban. Mostantól a pizzagyártó cég sokféle feltétet (vagy dekorátort) készíthet a ToppingDecorator osztály segítségével. Tegyük fel, hogy egy pizzához háromféle feltét lehet, mégpedig sajt, pepperoni és gomba.
Sajtos öntet
nyilvánososztálySajtkiterjedTopping Dekorátor{
magán Pizza pizza;nyilvánosSajt(Pizza pizza){
ez.pizza = pizza;
}@Felülbírálás
nyilvános Húr leírás(){
Visszatérés pizza.description() + ", sajtos öntet";
}
@Felülbírálás
nyilvánoskettősköltség(){
Visszatéréspizza.költség() + 2.50;
}
}
Pepperoni öntet
nyilvánososztályPepperonikiterjedTopping Dekorátor{
magán Pizza pizza;nyilvánosPepperoni(Pizza pizza){
ez.pizza = pizza;
}@Felülbírálás
nyilvános Húr leírás(){
Visszatérés pizza.description() + ", Pepperoni öntet";
}
@Felülbírálás
nyilvánoskettősköltség(){
Visszatéréspizza.költség() + 3.50;
}
}
Gomba öntet
nyilvánososztályGombakiterjedTopping Dekorátor{
magán Pizza pizza;nyilvánosGomba(Pizza pizza){
ez.pizza = pizza;
}
@Felülbírálás
nyilvános Húr leírás(){
Visszatérés pizza.description() + ", gomba öntet";
}
@Felülbírálás
nyilvánoskettősköltség(){
Visszatéréspizza.költség() + 4.50;
}
}
Most már van egy egyszerű alkalmazás, amelyet a dekorátor tervezési mintájával valósítottak meg. Ha egy ügyfél élesztős héjas pizzát rendelne sajttal és pepperonival, az adott forgatókönyv tesztkódja a következőképpen fog kinézni:
nyilvánososztályFő{
nyilvánosstatikusüresfő-(String[] args){
Pizza pizza1 = új YeastCrustPizza();
pizza1 = új Pepperoni (pizza1);
pizza1 = új sajt (pizza1);
System.out.println (pizza1.description() + " $" + pizza1.költség());
}
}
A kód futtatása a következő kimenetet eredményezi a konzolon:
Amint láthatja, a kimeneten a pizza típusa és összköltsége szerepel. A pizza élesztős kérges pizzaként indult 18,00 dollárért, de a díszítő mintával az alkalmazás új funkciókat és azok megfelelő költségét tudta hozzáadni a pizzához. Így új viselkedést ad a pizzának a meglévő kód megváltoztatása nélkül (az élesztőhéjú pizza).
A dekorátor mintával ugyanazt a viselkedést tetszőleges számú alkalommal alkalmazhatja egy tárgyon. Ha az ügyfél olyan pizzát rendel, amelyen minden rajta van, és némi extra sajttal, frissítheti a fő osztályt a következő kóddal, hogy tükrözze ezt:
Pizza pizza2 = új YeastCrustPizza();
pizza2 = új Pepperoni (pizza2);
pizza2 = új sajt (pizza2);
pizza2 = új sajt (pizza2);
pizza2 = új Gomba (pizza2);System.out.println (pizza2.description() + " $" + pizza2.költség());
A frissített alkalmazás a következő kimenetet produkálja a konzolon:
A Decorator Design Pattern használatának előnyei
A dekoratőr tervezési minta használatának két fő előnye a biztonság és a rugalmasság. A díszítő minta lehetővé teszi, hogy biztonságosabb kódot fejlesszen ki, anélkül, hogy beleavatkozna a már meglévő biztonságos kódba. Ehelyett kiterjeszti a meglévő kódot a kompozíción keresztül. Hatékonyan megakadályozza az új hibák vagy nem kívánt mellékhatások megjelenését.
Az összetételnek köszönhetően az előhívónak is nagy rugalmassága van a dekorátor minta használatakor. Bármikor telepíthet új dekorátort, hogy új viselkedést adjon hozzá anélkül, hogy megváltoztatná a meglévő kódot és megzavarná az alkalmazást.