Project Technical Lead
Návrhové vzory Java (design patterns): Composite
Dnes sa pozrieme na ďalší návrhový vzor Composite (java design patterns) z kategórie štrukturálnych vzorov (structural patterns). Návrhové vzory v tejto kategórii sa zaoberajú štruktúrou triedy, ako je dedičnosť (inheritance) a kompozícia (composition).
Prečítaj si o ďalších design patterns – seriál návrhových vzorov:
- Design pattern Singleton
- Design pattern Builder
- Design pattern Prototype
- Design pattern Factory
- Design pattern Abstract factory
- Design pattern Bridge
Čo to je návrhový vzor Composite?
Design pattern Composite (kompozit) je návrhový vzor, ktorý sa používa na vytvorenie stromovej štruktúry objektov, ktorá umožňuje klientovi pracovať s jednotlivými objektmi a ich zoskupeniami (kompozitmi) rovnakým spôsobom, pretože majú rovnaké rozhranie.
Aký problém návrhový vzor Composite rieši?
Pri práci so stromovou štruktúrou musia programátori často rozlišovať medzi listovým uzlom a vetvou. Vďaka tomu je kód zložitejší, a preto je náchylnejší na chyby. Riešením je rozhranie, ktoré umožňuje jednotne zaobchádzať so zložitými a primitívnymi objektmi.
Problém, ktorý Composite rieši, je potreba pracovať s objektami a ich kompozitmi jednotným spôsobom. Tým umožňuje klientovi rekurzívne prechádzať a manipulovať s celou stromovou štruktúrou, pričom nepotrebujeme rozlišovať medzi jednotlivými objektami a ich zoskupeniami.
Príklad Composite implementácie v Jave
Teraz si ukážeme ako implementovať vzor Composite v Jave. Vytvoríme si komplexnú stromovú štruktúru zloženú z individuálnych objektov (listov) aj kompozícií objektov (vetiev). Použitím vzoru Composite dosiahneme jednotné vykonávanie operácií na jednotlivých častí stromu nezávisle od typu.
Rozhranie CastStromu reprezentuje spoločné rozhranie pre listové uzly (List) aj zložené uzly (Vetva). Toto rozhranie definuje metódu vykonajOperaciu(), ktorá je kľúčová pre tento vzor.
CastStromu.java
package designpatterns;
// CastStromu - rozhranie pre všetky objekty v strome
public interface CastStromu {
void vykonajOperaciu();
}
Trieda List reprezentuje listový komponent v hierarchii. Implementuje rozhranie CastStromu a poskytuje implementáciu metódy vykonajOperaciu(). Listové komponenty nemajú žiadne podriadené prvky a vykonávajú operácie.
List.java
package designpatterns;
// List - konkrétna časť stromu reprezentujúca list v strome
public class List implements CastStromu {
private String id;
public List(String id) {
this.id = id;
}
public void vykonajOperaciu() {
System.out.println("Vykonávam operáciu na liste s názvom: " + id);
}
}
Trieda Vetva reprezentuje zložený komponent v hierarchii. Tiež implementuje rozhranie CastStromu a udržuje kolekciu (castiStromu) podriadených komponentov, ktoré môžu byť buď listové komponenty, alebo iné zložené komponenty.
Metóda pridajCast() umožňuje pridávať podriadené komponenty a tým konštruovať hierarchickú štruktúru.
Vetva.java
package designpatterns;
import java.util.ArrayList;
// Konkrétna časť stromu reprezentujúca vetvu v strome
public class Vetva implements CastStromu {
private String id;
private java.util.List<CastStromu> castiStromu = new ArrayList<>();
public Vetva(String id) {
this.id = id;
}
public void pridajCast(CastStromu cast) {
castiStromu.add(cast);
}
public void vykonajOperaciu() {
System.out.println("Vykonávam operáciu na vetve s názvom: " + id);
for (CastStromu cast : castiStromu) {
cast.vykonajOperaciu();
}
}
}
V metóde main je vytvorená inštancia koreňového zloženého komponentu (kmenovaVetva) a k nemu sú pridané podriadené komponenty (ako listové, tak zložené).
Keď je zavolaná metóda vykonajOperaciu() na kmeňovom komponente (kmenovaVetva), rekurzívne zavolá metódu vykonajOperaciu() na všetkých podriadených komponentoch, čo vedie k vykonaniu operácií na celej štruktúre.
Main.java
import designpatterns.*;
public class Main {
public static void main(String[] args) {
// Vytvorí strom z listov a vetiev
System.out.println("Skladám strom z kmeňa, listov a vetiev.");
List list1 = new List("List 1");
List list2 = new List("List 2");
List list3 = new List("List 3");
Vetva vetva1 = new Vetva("Vetva 1");
vetva1.pridajCast(list1);
vetva1.pridajCast(list2);
Vetva vetva2 = new Vetva("Vetva 2");
vetva2.pridajCast(list3);
Vetva kmenovaVetva = new Vetva("Kmeň");
kmenovaVetva.pridajCast(vetva1);
kmenovaVetva.pridajCast(vetva2);
// Vykonáva operáciu na celej stromovej štruktúre
kmenovaVetva.vykonajOperaciu();
}
}
Výstup z tohto príkladu je:
Zhrnutie Java Composite
Návrhový vzor Composite sa používa v situácii, keď je potrebné pracovať jednotne s jednotlivými objektami aj ich zoskupeniami.
Pripravili sme pre teba súbory so spomínaným príkladom vo forme kódu, ktorý si môžeš spustiť priamo v Jave. Stiahni si kód Java Composite tu.