Cześć! Dzisiaj przyjrzymy się bliżej jednej zasadzie programowania obiektowego (OOP): dziedziczeniu. Przyjrzymy się także innym typom relacji między klasami: kompozycji i agregacji.
Ten temat nie będzie trudny: już wielokrotnie spotkałeś się z dziedziczeniem i przykładami dziedziczenia na poprzednich lekcjach. Dzisiaj najważniejsze będzie utrwalenie swojej wiedzy, dokładniejsze zbadanie mechanizmu dziedziczenia i jeszcze raz przytoczenie kilku przykładów. :) Dobrze chodźmy!
Kiedy mamy kilkadziesiąt klas samochodów, ilość duplikatów kodu staje się naprawdę poważna. Przeniesienie wspólnych pól i metod (zwanych także „stanami” i „zachowaniami”) do klasy nadrzędnej pozwala nam zaoszczędzić dużo czasu i miejsca. Jeśli jakiś typ ma unikalne właściwości lub metody, których nie mają inne typy samochodów, nic wielkiego. Zawsze możesz je utworzyć w klasie potomnej, oddzielnej od wszystkich innych.
To samo dotyczy pól: jeśli klasa potomna ma unikalne właściwości, spokojnie deklarujemy te pola wewnątrz klasy potomnej i przestajemy się martwić. :) Możliwość ponownego użycia kodu to główna zaleta dziedziczenia. Dla programistów bardzo ważne jest, aby nie pisać dodatkowego kodu. Spotkasz się z tym wielokrotnie w swojej pracy. Proszę pamiętać o jeszcze jednej ważnej rzeczy: Java nie ma wielokrotnego dziedziczenia. Każda klasa dziedziczy tylko jedną klasę. Porozmawiamy więcej o przyczynach tego stanu rzeczy na kolejnych lekcjach. Na razie po prostu o tym pamiętaj. Nawiasem mówiąc, to sprawia, że Java różni się od niektórych innych języków OOP. Na przykład język C++ obsługuje dziedziczenie wielokrotne. Przy dziedziczeniu wszystko jest mniej więcej jasne. Przejdźmy dalej.

Dziedziczenie w Javie i jego zalety
Jak zapewne pamiętasz, dziedziczenie jest mechanizmem, który pozwala opisać nową klasę w oparciu o istniejącą klasę (klasę nadrzędną). W ten sposób nowa klasa pożycza właściwości i funkcjonalność klasy nadrzędnej. Przypomnijmy przykład dziedziczenia podany na poprzednich lekcjach:
public class Car {
private String model;
private int maxSpeed;
private int yearOfManufacture;
public Car(String model, int maxSpeed, int yearOfManufacture) {
this.model = model;
this.maxSpeed = maxSpeed;
this.yearOfManufacture = yearOfManufacture;
}
public void gas() {
// Gas
}
public void brake() {
// Brake
}
}
public class Truck extends Car {
public Truck(String model, int maxSpeed, int yearOfManufacture) {
super(model, maxSpeed, yearOfManufacture);
}
}
public class Sedan extends Car {
public Sedan(String model, int maxSpeed, int yearOfManufacture) {
super(model, maxSpeed, yearOfManufacture);
}
}
Mamy pewien program, który obejmuje pracę z różnymi typami samochodów. Nawet jeśli nie jesteś entuzjastą samochodów, prawdopodobnie wiesz, że na świecie jest bardzo wiele rodzajów samochodów. :) W związku z tym podzielimy wspólne właściwości samochodów na wspólną klasę nadrzędną o nazwie Car
. Co jest zatem wspólne dla wszystkich samochodów, niezależnie od ich typu? Każdy samochód ma rok produkcji, nazwę modelu i maksymalną prędkość. Umieszczamy te właściwości w polach model
, maxSpeed
, i yearOfManufacture
. Jeśli chodzi o zachowanie, każdy samochód może przyspieszać i zwalniać. :) Definiujemy to zachowanie w gas()
andbrake()
metody. Jakie korzyści nam to daje? Przede wszystkim zmniejsza ilość kodu. Oczywiście możemy obejść się bez klasy nadrzędnej. Ale ponieważ każdy samochód musi być w stanie przyspieszać i zwalniać, będziemy musieli stworzyć metody gas()
i brake()
w klasach Truck
, Sedan
, F1Car
, i SportsCar
oraz w każdej innej klasie samochodów. Wyobraź sobie, ile dodatkowego kodu musielibyśmy napisać. I nie zapomnij o polach model
, maxSpeed
, i yearOfManufacture
: jeśli pozbędziemy się klasy nadrzędnej, będziemy musieli je utworzyć w każdej klasie samochodów! 
public class F1Car extends Car {
public void pitStop() {
// Only race cars make pit stops
}
public static void main(String[] args) {
F1Car formula1Car = new F1Car();
formula1Car.gas();
formula1Car.pitStop();
formula1Car.brake();
}
}
Spójrzmy na przykład na samochody wyścigowe Formuły 1. W przeciwieństwie do swoich „krewnych” mają wyjątkowe zachowanie — od czasu do czasu robią sobie pit stop. To nam nie przeszkadza. Opisaliśmy już typowe zachowanie w Car
klasie nadrzędnej, a specyficzne zachowanie klas potomnych można dodać do tych klas. 
Skład i agregacja
Klasy i obiekty można ze sobą łączyć. Dziedziczenie opisuje relację „jest-a”. Lew jest zwierzęciem. Taki związek można łatwo wyrazić za pomocą dziedziczenia, gdzieAnimal
jest klasą nadrzędną i Lion
jest dzieckiem. Jednak nie wszystkie relacje są opisywane w ten sposób. Na przykład klawiatura jest zdecydowanie powiązana z komputerem, ale nie jest komputerem . Ręce są w jakiś sposób związane z osobą, ale nie są osobą. W takich przypadkach mamy do czynienia z innym typem relacji: nie „jest-a”, ale „ma-a”. Ręka nie jest osobą, ale jest częścią osoby. Klawiatura nie jest komputerem, ale jest częścią komputera. Relację ma-powiązanie można opisać w kodzie za pomocą kompozycji i agregacji. Różnica polega na „surowości” relacji. Podajmy prosty przykład: mamy klasę Car
. Każdy samochód ma silnik. Dodatkowo każdy samochód ma pasażerów. Jaka jest podstawowa różnica między polami Engine engine
i Passenger[] passengers
? To, że pasażer A
siedzi w samochodzie, nie oznacza, że pasażerów B
i C
nie ma w samochodzie. Samochód może odpowiadać wielu pasażerom. Co więcej, nawet jeśli wszyscy pasażerowie wysiądą z samochodu, nadal będzie on działał płynnie. Relacja między Car
klasą a Passenger[] passengers
tablicą jest mniej ścisła. Nazywa się to agregacją . Stanowi kolejny dobry przykład agregacji. Załóżmy, że mamy Student
klasę i aStudentGroup
klasa. Student może dołączyć do wielu organizacji studenckich: klubu fizyki, fanklubu Gwiezdnych Wojen i/lub studenckiego klubu komediowego. Kompozycja jest ściślejszym rodzajem relacji. W przypadku kompozycji obiekt jest częścią jakiegoś obiektu i nie może należeć do innego obiektu tego samego typu. Najprostszym przykładem jest silnik samochodowy. Silnik jest częścią samochodu i nie może być częścią innego samochodu. Jak widać, ich związek jest znacznie ściślejszy niż związek między Car
i Passengers
. 
Więcej czytania: |
---|
GO TO FULL VERSION