Menu
Coddy logo textTech

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.

challenge icon

Wyzwanie

Łatwy

Zbudujmy 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ą OrganizationUnit z getterem name, metodą getSalaryBudget(), która zwraca wartość typu int, oraz metodą display([String indent = '']) do wyświetlania hierarchii. Zbuduj klasę Employee (liść), która implementuje OrganizationUnit. Powinna mieć nazwę i wynagrodzenie, a metoda getSalaryBudget() powinna zwracać wynagrodzenie pracownika. Jej metoda display() powinna wyświetlać [indent]- [name] ($[salary]). Następnie utwórz klasę Department (kompozyt), która również implementuje OrganizationUnit. Powinna mieć nazwę i przechowywać listę elementów potomnych typu OrganizationUnit. Dodaj metodę add(), aby dodawać pracowników lub poddziały. Jej metoda getSalaryBudget() powinna rekurencyjnie sumować budżety wszystkich elementów potomnych. Metoda display() 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ł Engineering zawierający dwoje pracowników: Alice z wynagrodzeniem 80000 oraz Bob z wynagrodzeniem 75000. Utwórz dział QA z jednym pracownikiem: Carol z wynagrodzeniem 65000. Następnie utwórz dział Technology i dodaj do niego działy Engineering oraz QA jako poddziały. Wywołaj display() dla działu Technology, a następnie wyświetl Total 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: $220000

Spró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ń
}
quiz iconSprawdź się

Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.

Wszystkie lekcje w sekcji Programowanie obiektowe

Poćwicz samodzielnie: Kompilator Dart online