Wzorzec kompozytu
Część sekcji Programowanie obiektowe ścieżki Dart w Coddy. Lekcja 99 z 110.
Wzorzec Composite pozwala jednolicie traktować pojedyncze obiekty i grupy obiektów. Łączy obiekty w struktury drzewiaste, w których zarówno pojedyncze elementy, jak i ich kolekcje mają ten sam interfejs. Doskonale nadaje się do przedstawiania hierarchii, takich jak systemy plików, schematy organizacyjne czy komponenty interfejsu użytkownika.
Wzorzec ma dwa typy uczestników: węzły Leaf (pojedyncze obiekty bez dzieci) oraz węzły Composite (kontenery zawierające inne komponenty). Oba implementują wspólny interfejs Component:
abstract class FileSystemItem {
String get name;
int getSize();
void display([String indent = '']);
}
class File implements FileSystemItem {
@override
final String name;
final int size;
File(this.name, this.size);
@override
int getSize() => size;
@override
void display([String indent = '']) {
print('$indent- $name ($size KB)');
}
}
class Folder implements FileSystemItem {
@override
final String name;
final List<FileSystemItem> _children = [];
Folder(this.name);
void add(FileSystemItem item) => _children.add(item);
@override
int getSize() => _children.fold(0, (sum, item) => sum + item.getSize());
@override
void display([String indent = '']) {
print('$indent+ $name/');
for (var child in _children) {
child.display('$indent ');
}
}
}
void main() {
var docs = Folder('Documents');
docs.add(File('resume.pdf', 150));
docs.add(File('photo.jpg', 2400));
var projects = Folder('Projects');
projects.add(File('main.dart', 25));
docs.add(projects);
docs.display();
print('Total: ${docs.getSize()} KB');
}Klasa Folder może zawierać zarówno obiekty File, jak i inne obiekty Folder. Gdy wywołujesz getSize() dla folderu, metoda rekurencyjnie oblicza łączny rozmiar całej jego zawartości. Kod klienta nie musi wiedzieć, czy pracuje z pojedynczym plikiem, czy z całą hierarchią folderów — oba przypadki obsługują te same metody.
Wyzwanie
ŁatwyZbudujmy system schematu organizacyjnego z użyciem wzorca Composite! Utworzysz strukturę, w której zarówno pojedynczy pracownicy, jak i działy (zawierające pracowników i inne działy) mogą być traktowani jednolicie — idealne rozwiązanie do przedstawiania hierarchii firmowej.
Podzielisz kod na dwa pliki:
organization.dart: Ten plik zawiera interfejs komponentu oraz klasy liścia i kompozytu. Utwórz klasę abstrakcyjnąOrganizationUnitz getteremname, metodągetSalaryBudget(), która zwraca wartość typuint, oraz metodądisplay([String indent = ''])do wyświetlania hierarchii. Zbuduj klasęEmployee(liść), która implementujeOrganizationUnit. Powinna mieć nazwę i wynagrodzenie, a metodagetSalaryBudget()powinna zwracać wynagrodzenie pracownika. Jej metodadisplay()powinna wyświetlać[indent]- [name] ($[salary]). Następnie utwórz klasęDepartment(kompozyt), która również implementujeOrganizationUnit. Powinna mieć nazwę i przechowywać listę elementów potomnych typuOrganizationUnit. Dodaj metodęadd(), aby dodawać pracowników lub poddziały. Jej metodagetSalaryBudget()powinna rekurencyjnie sumować budżety wszystkich elementów potomnych. Metodadisplay()powinna wyświetlać[indent]+ [name]/, a następnie wyświetlać każdy element potomny z większym wcięciem (dodaj dwie spacje).main.dart: Zaimportuj plik organizacji i zbuduj strukturę firmy. Utwórz działEngineeringzawierający dwoje pracowników:Alicez wynagrodzeniem80000orazBobz wynagrodzeniem75000. Utwórz działQAz jednym pracownikiem:Carolz wynagrodzeniem65000. Następnie utwórz działTechnologyi dodaj do niego działyEngineeringorazQAjako poddziały. Wywołajdisplay()dla działu Technology, a następnie wyświetlTotal Budget: $, po którym podaj łączny budżet wynagrodzeń.
Zaletą wzorca Composite jest to, że Technology.getSalaryBudget() automatycznie oblicza sumę budżetów wszystkich zagnieżdżonych działów i pracowników — kod klienta nie musi znać struktury wewnętrznej!
Oczekiwany wynik:
+ Technology/
+ Engineering/
- Alice ($80000)
- Bob ($75000)
+ QA/
- Carol ($65000)
Total Budget: $220000Spróbuj swoich sił
import 'organization.dart';
void main() {
// TODO: Utwórz dział Engineering
// TODO: Dodaj Alice z wynagrodzeniem 80000
// TODO: Dodaj Bob z wynagrodzeniem 75000
// TODO: Utwórz dział QA
// TODO: Dodaj Carol z wynagrodzeniem 65000
// TODO: Utwórz dział Technology
// TODO: Dodaj Engineering i QA jako poddziały
// TODO: Wywołaj display() dla działu Technology
// TODO: Wypisz "Total Budget: $", a następnie łączny budżet wynagrodzeń
}
Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.
Wszystkie lekcje w sekcji Programowanie obiektowe
1Podstawy OOP
Pliki zewnętrzneBiblioteki i importyWprowadzenie do OOPKlasy a obiektySłowo kluczowe thisMetodyZmienne instancjiPodstawy konstruktorówPowtórka – prosty kalkulator4Bezpieczeństwo wartości null
Wprowadzenie do bezpieczeństwa wartości nullTypy dopuszczające null i niedopuszczające nullOperatory ? i !Słowo kluczowe late a bezpieczeństwo wartości nullOperatory uwzględniające nullBezpieczeństwo wartości null w klasachPodsumowanie — system profili użytkowników7Klasy abstrakcyjne i interfejsy
Klasy abstrakcyjneMetody abstrakcyjneInterfejsy w DartInterfejsy niejawneImplementowanie a rozszerzanieWiele interfejsówPowtórka — kalkulator kształtów10Kolekcje i typy generyczne
Przegląd List, Set i MapKolekcje bezpieczne typowoKlasy generyczneMetody generyczneOgraniczenia typów generycznychIterable i IteratorPowtórka — generyczne przechowywanie danych13Zaawansowane koncepcje OOP
Kompozycja a dziedziczenieMetody rozszerzająceKlasy wywoływalneKlasy zapieczętowane (Dart 3)Rekordy (Dart 3)Wzorce i dopasowywanie (3.0)Typy wyliczeniowe z metodami16Projekt: Zarządzanie biblioteką
Omówienie projektuKlasy książek i użytkowników2Konstruktory w Dart
Konstruktor domyślnyKonstruktory nazwaneListy inicjalizująceKonstruktory stałeKonstruktory fabryczneKonstruktory przekierowującePodsumowanie — budowanie kształtów5Hermetyzacja
Elementy publiczne a prywatneKonwencja prefiksu _Prywatność na poziomie bibliotekiGettery i settery — szczegółowoUkrywanie informacjiPodsumowanie — dane uczniów8Domieszki
Wprowadzenie do domieszekTworzenie domieszekKorzystanie z wielu domieszekSłowo kluczowe on w domieszkachDomieszka a dziedziczenieDomieszka a interfejsPodsumowanie – system zwierząt11Metody specjalne
Nadpisanie toString()Nadpisanie hashCode i ==Interfejs ComparableMetoda call()Nadpisanie noSuchMethodPodsumowanie — własna kolekcja14Wzorce projektowe, część 1
Wprowadzenie do wzorców projektowychWzorzec SingletonWzorzec FactoryWzorzec ObserverWzorzec Strategy3Właściwości klas
Elementy instancji a elementy statycznePola final i constZmienne inicjalizowane z opóźnieniemMetody i pola statyczneGettery i setteryPowtórzenie – menedżer kont bankowych6Dziedziczenie
Podstawy dziedziczeniaSłowo kluczowe superPrzesłanianie metodAdnotacja @overrideSłowo kluczowe final dla klasKonstruktory i dziedziczeniePowtórzenie – hierarchia pracowników9Polimorfizm
Podstawy polimorfizmuPolimorfizm za pomocą interfejsówSprawdzanie typu w czasie działaniaOperatory is i asSłowo kluczowe covariantPodsumowanie — procesor płatności12Asynchroniczne OOP
Futures i async/awaitPodstawy strumieniKontrolery strumieniKonstruktory asynchroniczneAsynchroniczność w metodach klasyPodsumowanie — pobieranie danych15Wzorce projektowe, część 2
Wzorzec poleceniaWzorzec adapteraWzorzec dekoratoraWzorzec metody szablonowejWzorzec stanuWzorzec kompozytuWzorzec repozytoriumPoćwicz samodzielnie: Kompilator Dart online