Cititorii ca tine ajută la sprijinirea MUO. Când efectuați o achiziție folosind link-uri de pe site-ul nostru, este posibil să câștigăm un comision de afiliat. Citeşte mai mult.

Unul dintre cele mai importante principii în dezvoltarea de software este principiul de proiectare deschis-închis. Acest principiu de proiectare subliniază faptul că clasele ar trebui să fie deschise pentru extindere, dar închise pentru modificare. Modelul de design al decoratorului întruchipează principiul de design deschis-închis.

Cu modelul de design al decoratorului, puteți extinde cu ușurință o clasă oferindu-i un comportament nou, fără a modifica codul existent. Modelul decorator face acest lucru dinamic în timpul rulării, folosind compoziția. Acest model de design este cunoscut ca o alternativă flexibilă la utilizarea moștenirii pentru a extinde comportamentul.

Cum funcționează modelul de design al decoratorului?

Deși modelul decorator este o alternativă la moștenirea de clasă, încorporează unele aspecte ale moștenirii în designul său. Un aspect cheie al modelului de decorator este că toate clasele sale sunt legate, fie direct, fie indirect.

instagram viewer

Un model tipic de design de decorator are următoarea structură:

Din diagrama de clase de mai sus puteți vedea că modelul de decorator are patru clase majore.

componenta: aceasta este o clasă abstractă (sau interfață), care servește ca supertip pentru modelul de decorator.

Componenta betonului: acestea sunt obiectele pe care le puteți decora cu diferite comportamente în timpul execuției. Ei moștenesc din interfața componentelor și implementează funcțiile sale abstracte.

Decorator: această clasă este abstractă și are același supertip ca și obiectul pe care îl va decora. În diagrama de clasă, veți vedea două relații între clasele componente și decorator. Prima relație este una de moștenire; fiecare decorator este o componentă. A doua relație este una de compoziție; fiecare decorator are o (sau împachetează o) componentă.

ConcreteDecorator: aceștia sunt decoratorii individuali care conferă unei componente un comportament specific. Trebuie să rețineți că fiecare decorator de beton are o variabilă de instanță care conține o referință la o componentă.

Implementarea modelului de design al decoratorului în Java

Un exemplu de aplicație de comandă de pizza poate demonstra în mod adecvat cum să utilizați modelul de decorator pentru a dezvolta aplicații. Acest exemplu de aplicație pentru pizza permite clienților să comande pizza cu mai multe topping-uri. Prima clasă a modelului de decorator este interfața pizza:

publicinterfațăPizza{
publicabstract Şir Descriere();
publicabstractdublacost();
}

Interfața Pizza este clasa de componente. Deci, puteți crea una sau mai multe clase concrete din acesta. Compania de pizza face două tipuri principale de pizza, pe bază de aluat. Un tip de pizza are aluat de drojdie:

publicclasăYeastCrustPizzauneltePizza{
@Trece peste
public Şir Descriere(){
întoarcere"Aluat de pizza facut cu drojdie";
}

@Trece peste
publicdublacost(){
întoarcere18.00;
}
}

YeastCrustPizza este primul beton Clasa Java a interfeței Pizza. Celălalt tip de pizza disponibil este pâinea:

publicclasăFlatbreadCrustPizzauneltePizza{
@Trece peste
public Şir Descriere(){
întoarcere„Aluat de pizza făcut cu pâine”;
}

@Trece peste
publicdublacost(){
întoarcere15.00;
}
}

Clasa FlatbreadCrustPizza este a doua componentă concretă și, ca și clasa YeastCrustPizza, implementează toate funcțiile abstracte ale interfeței Pizza.

Decoratorii

Clasa de decorator este întotdeauna abstractă, așa că nu puteți crea o instanță nouă direct din ea. Dar este necesar să se stabilească o relație între diferiții decoratori și componentele pe care le vor decora.

publicabstractclasăToppingDecoratoruneltePizza{
public Şir Descriere(){
întoarcere„Topping necunoscut”;
}
}

Clasa ToppingDecorator reprezintă clasa decoratorului din această aplicație exemplu. Acum, compania de pizza poate crea multe toppinguri (sau decoratori) diferite, folosind clasa ToppingDecorator. Să presupunem că o pizza poate avea trei tipuri diferite de toppinguri, și anume brânză, pepperoni și ciuperci.

Topping de brânză

publicclasăBrânzăse extindeToppingDecorator{
privat Pizza pizza;

publicBrânză(Pizza pizza){
acest.pizza = pizza;
}

@Trece peste
public Şir Descriere(){
întoarcere pizza.descriere() + ", Topping de brânză";
}

@Trece peste
publicdublacost(){
întoarcerepizza.cost() + 2.50;
}
}

Topping pepperoni

publicclasăPepperonise extindeToppingDecorator{
privat Pizza pizza;

publicPepperoni(Pizza pizza){
acest.pizza = pizza;
}

@Trece peste
public Şir Descriere(){
întoarcere pizza.descriere() + ", Topping pepperoni";
}

@Trece peste
publicdublacost(){
întoarcerepizza.cost() + 3.50;
}
}

Topping cu ciuperci

publicclasăCiupercăse extindeToppingDecorator{
privat Pizza pizza;

publicCiupercă(Pizza pizza){
acest.pizza = pizza;
}

@Trece peste
public Şir Descriere(){
întoarcere pizza.descriere() + ", Topping de ciuperci";
}

@Trece peste
publicdublacost(){
întoarcerepizza.cost() + 4.50;
}
}

Acum aveți o aplicație simplă implementată folosind modelul de design al decoratorului. Dacă un client ar comanda o pizza cu crustă de drojdie cu brânză și pepperoni, codul de testare pentru acel scenariu va arăta după cum urmează:

publicclasăPrincipal{
publicstaticgolprincipal(Șir[] argumente){
Pizza pizza1 = nou YeastCrustPizza();
pizza1 = nou Pepperoni (pizza1);
pizza1 = nou Brânză (pizza1);
System.out.println (pizza1.description() + " $" + pizza1.cost());
}
}

Rularea acestui cod va produce următoarea ieșire în consolă:

După cum puteți vedea, rezultatul indică tipul de pizza împreună cu costul total al acesteia. Pizza a început ca o pizza cu crusta de drojdie pentru 18,00 USD, dar cu modelul de decorator, aplicația a putut adăuga noi caracteristici și costul lor adecvat la pizza. Astfel, oferindu-i pizza un comportament nou, fără a modifica codul existent (pizza cu crusta de drojdie).

Cu modelul decorator, puteți aplica același comportament unui obiect de câte ori doriți. Dacă un client comandă o pizza cu totul pe ea și niște brânză în plus, puteți actualiza clasa principală cu următorul cod pentru a reflecta acest lucru:

Pizza pizza2 = nou YeastCrustPizza();
pizza2 = nou Pepperoni (pizza2);
pizza2 = nou Brânză (pizza2);
pizza2 = nou Brânză (pizza2);
pizza2 = nou Ciuperci (pizza2);

System.out.println (pizza2.description() + " $" + pizza2.cost());

Aplicația actualizată va produce următoarea ieșire în consolă:

Avantajele utilizării modelului de design al decoratorului

Cele două avantaje majore ale utilizării modelului de design al decoratorului sunt securitatea și flexibilitatea. Modelul decorator vă permite să dezvoltați un cod mai sigur, fără a interfera cu codul securizat preexistent. În schimb, extinde codul existent prin compoziție. Prevenirea eficientă a introducerii de noi bug-uri sau a efectelor secundare neintenționate.

Datorită compoziției, un dezvoltator are, de asemenea, multă flexibilitate atunci când folosește modelul decorator. Puteți implementa un nou decorator în orice moment pentru a adăuga un comportament nou, fără a modifica codul existent și a întrerupe aplicația.