1. Wspólna klasa bazowa
Dzisiaj będziemy cieszyć się szwedzkim stołem ciekawych tematów. Pamiętasz, jak wprowadziliśmy ChessItem
klasę bazową, aby uprościć wszystkie klasy reprezentujące figury szachowe? Mam taką nadzieję 🙂
Teraz wyobraź sobie, że każdy kawałek ma draw()
metodę, która obsługuje rysowanie go na ekranie. Wywołujesz draw()
metodę, a element rysuje się w swoich bieżących współrzędnych. Wygodnie byłoby przenieść tę metodę do klasy bazowej.
Gdyby draw()
metoda znajdowała się w klasie bazowej ChessItem, moglibyśmy nadpisać ją w klasach figur i napisać elegancki kod w następujący sposób:
class ChessBoard
{
public void drawAllChessItems()
{
// Add the pieces to the list
ArrayList<ChessItem> items = new ArrayList<ChessItem>();
items.add(new King());
items.add(new Queen());
items.add(new Bishop());
// Draw them regardless of their type
for(ChessItem item: items)
{
item.draw();
}
}
}
Wprowadzając ChessItem
klasę bazową, udało nam się znacznie uprościć kod: nie ma potrzeby wywoływania metod każdej klasy z osobna, możemy łatwo przechowywać wszystkie obiekty w jednej kolekcji itp.
Ale tutaj pojawia się ciekawe pytanie: co powinna narysować na ekranie draw()
metoda zadeklarowana bezpośrednio w klasie? ChessItem
W końcu w szachach nie ma takiej figury, więc nie ma co rysować.
Dokładnie tak. Co więcej, tworzenie ChessItem
obiektów bezpośrednio nie ma sensu. To nie jest figura szachowa, ale raczej abstrakcja — klasa, którą stworzyliśmy dla naszej wygody. Tak działa abstrakcja w OOP : przenosimy ważne dane i metody (te wspólne dla wszystkich elementów) do klasy bazowej i zachowujemy ich różnice w oddzielnych klasach potomnych.
2. Zajęcia abstrakcyjne
W takich sytuacjach Java ma specjalny rodzaj klasy: klasę abstrakcyjną . Zostały zaprojektowane tak, aby ułatwić programistom pracę z podobnymi klasami i zmniejszyć ilość powielanego w nich kodu.
Oto trzy rzeczy, które warto wiedzieć o klasach abstrakcyjnych.
Metoda bez implementacji
Klasa abstrakcyjna może mieć deklarację metody bez implementacji. Właśnie to sprawia, że metoda jest abstrakcyjna. Treść metody jest po prostu zastępowana średnikiem. A przed nazwą metody piszemy słowo abstract
kluczowe. Przykład:
public abstract class ChessItem
{
public int x, y; // Coordinates
private int value; // The piece's value
public int getValue() // Ordinary method that returns value field
{
return value;
}
public abstract void draw(); // Abstract method. The implementation is missing.
}
Klasa abstrakcyjna
Każda metoda bez implementacji jest oznaczona słowem kluczowym abstract. Jeśli klasa ma choć jedną metodę abstrakcyjną, klasa jest również oznaczona słowem abstract
kluczowym.
Zakaz tworzenia obiektów
Nie można tworzyć obiektów klasy abstrakcyjnej . Taki kod po prostu się nie skompiluje.
Kod | Opis |
---|---|
|
Ten kod się nie kompiluje : |
|
Ale możesz to zrobić |
Dziedziczenie klasy abstrakcyjnej
Jeśli twoja klasa dziedziczy klasę abstrakcyjną, musisz nadpisać wszystkie odziedziczone metody abstrakcyjne, czyli napisać dla nich implementację. W przeciwnym razie sama twoja klasa również będzie musiała zostać uznana za abstrakcyjną.
Jeśli klasa ma choćby jedną niezaimplementowaną metodę zadeklarowaną bezpośrednio w niej lub odziedziczoną z klasy nadrzędnej, wówczas klasa jest uważana za abstrakcyjną.
I dlaczego to wszystko jest konieczne? Dlaczego potrzebne są klasy abstrakcyjne? Czy zamiast tego nie można użyć zwykłych? Czy zamiast abstrakcyjnych metod nie moglibyśmy po prostu napisać dwóch pustych nawiasów klamrowych jako treści metody?
Moglibyśmy. Ale te ograniczenia są podobne do private
modyfikatora. Używamy słowa kluczowego private, aby celowo uniemożliwić innym programistom bezpośredni dostęp do danych i zmusić ich do używania tylko naszych publicznych metod podczas pisania klas.
Tak samo jest z klasami abstrakcyjnymi. Autor klasy abstrakcyjnej nie chce, aby obiekty klasy były tworzone. Zamiast tego autor oczekuje, że metody abstrakcyjne będą dziedziczone z klasy abstrakcyjnej, a następnie nadpisywane.
Zaleta tego podejścia jest łatwo widoczna w dużych projektach. Im więcej masz klas, tym wyraźniej musisz określić ich role. Korzyści z takiego podejścia zobaczysz w niedalekiej przyszłości. Wszystko przez to przechodzi.