Menu
CoddyTech

Kompozycja a dziedziczenie

Część sekcji Programowanie obiektowe ścieżki Dart w Coddy. Lekcja 82 z 110.

Dowiedziałeś się, że dziedziczenie tworzy relację „jest” — Dog to Animal. Istnieje jednak inne potężne podejście: kompozycja, która tworzy relację „ma”. Zamiast dziedziczyć zachowanie, klasa zawiera instancje innych klas i deleguje im pracę.

Rozważ klasę Car. Przy dziedziczeniu możesz spróbować rozszerzyć klasę Engine — ale samochód nie jest silnikiem, lecz ma silnik:

class Engine {
  void start() => print('Engine started');
}

class Car {
  final Engine _engine = Engine();  // Kompozycja: Car MA Engine
  
  void start() {
    _engine.start();  // Przekaż wykonanie silnikowi
    print('Car is ready to drive');
  }
}

void main() {
  var car = Car();
  car.start();
}

Główną zaletą kompozycji jest elastyczność. W przypadku dziedziczenia jesteś ograniczony do jednej klasy nadrzędnej. W przypadku kompozycji możesz łączyć wiele komponentów, a nawet wymieniać je w czasie działania programu:

class ElectricEngine {
  void start() => print('Electric motor humming');
}

class HybridCar {
  Engine? _gasEngine;
  ElectricEngine? _electricEngine;
  
  HybridCar({bool useElectric = false}) {
    if (useElectric) {
      _electricEngine = ElectricEngine();
    } else {
      _gasEngine = Engine();
    }
  }
}

Popularna wskazówka brzmi: „przedkładaj kompozycję nad dziedziczenie”. Używaj dziedziczenia, gdy występuje prawdziwa relacja „jest czymś” i potrzebujesz polimorfizmu. Używaj kompozycji, gdy chcesz ponownie wykorzystać zachowanie bez ścisłego sprzężenia lub gdy obiekt potrzebuje możliwości z wielu źródeł.

challenge icon

Wyzwanie

Łatwy

Zbudujmy system komputerowy z użyciem kompozycji! Zamiast próbować sprawić, by komputer dziedziczył po swoich częściach, utworzysz osobne klasy komponentów i połączysz je ze sobą — ponieważ komputer ma procesor CPU i ma pamięć, a nie jest procesorem CPU ani pamięcią.

Podzielisz swój kod na trzy pliki:

  • components.dart: Utwórz dwie klasy komponentów reprezentujące części komputera:
    • Klasę CPU z polami String brand i double speedGHz. Dodaj metodę process(), która zwraca ciąg znaków: [brand] processing at [speedGHz]GHz
    • Klasę Memory z polem int sizeGB. Dodaj metodę load(), która zwraca ciąg znaków: Loading [sizeGB]GB of data
  • computer.dart: Utwórz klasę Computer, która używa kompozycji do połączenia komponentów. Twój komputer powinien:
    • Mieć pole String name
    • Zawierać instancje CPU i Memory (kompozycja — komputer MA te części)
    • Przyjmować wszystkie niezbędne wartości przez konstruktor, aby tworzyć oba komponenty wewnętrznie
    • Mieć metodę boot(), która deleguje zadania obu komponentom i wypisuje trzy wiersze: nazwę komputera, po której następuje starting..., następnie wynik metody process procesora CPU, a potem wynik metody load pamięci Memory
    • Mieć metodę specs(), która zwraca ciąg znaków opisujący system: [name]: [brand] [speedGHz]GHz, [sizeGB]GB RAM
  • main.dart: Zaimportuj swoje pliki i pokaż kompozycję w działaniu:
    • Utwórz obiekt Computer o nazwie Workstation z procesorem CPU Intel działającym z częstotliwością 3.5 GHz oraz 16 GB pamięci
    • Wywołaj metodę boot()
    • Wypisz wynik metody specs()

Zwróć uwagę, że klasa Computer nie rozszerza klasy CPU ani Memory — zawiera je i deleguje im zadania. To relacja „ma” tworzona przez kompozycję!

Oczekiwany wynik:

Workstation starting...
Intel processing at 3.5GHz
Loading 16GB of data
Workstation: Intel 3.5GHz, 16GB RAM

Spróbuj swoich sił

import 'computer.dart';

void main() {
  // TODO: Utwórz obiekt Computer o nazwie "Workstation" z:
  // - procesorem Intel pracującym z częstotliwością 3.5 GHz
  // - 16 GB pamięci

  // TODO: Wywołaj metodę boot()

  // TODO: Wypisz wynik specs()
}
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