2.1 Podstawowe koncepcje OOP
Podstawą podejścia obiektowego do programowania jest paradygmat OOP. To podejście, w którym wszystkie jednostki programu są traktowane jako obiekty. Obiekty to dane + metody/funkcje, które coś z tymi danymi robią.
Można również powiedzieć, że obiekt ma stan i zachowanie. Stan obiektu jest zapewniany przez jego dane, które przechowywane są w jego zmiennych wewnętrznych. Zachowanie obiektu to suma wszystkich działań wykonywanych przez jego metody.
W średnim programie jest wiele tysięcy obiektów, a w dużym — miliony. Aby jakoś zredukować chaos, zdecydowano się zorganizować obiekty w klasy, a klasy obiektów w pewną hierarchię.
Każdy obiekt ma klasę, z której jest tworzony. Z jednej strony klasa to wzorzec obiektu, a z drugiej strony — to niezależny obiekt ze swoimi cechami (o nich później).
Aby lepiej zrozumieć koncepcję klas, zapoznaj się z poniższymi definicjami:
Klasa — to wzorzec lub schemat do tworzenia obiektów, który określa atrybuty i metody charakterystyczne dla wszystkich obiektów tego typu. Klasy pozwalają organizować dane i funkcje, które z nimi pracują, w jedną całość.
Obiekt — instancja klasy. Każdy obiekt ma stan (definiowany przez atrybuty) i zachowanie (definiowane przez metody).
Enkapsulacja — polega na ukrywaniu wewnętrznej implementacji klasy i udostępnianiu interfejsu do interakcji z obiektami tej klasy. To pomaga chronić dane i zarządzać dostępem do nich.
Dziedziczenie — pozwala jednej klasie (potomnej) dziedziczyć atrybuty i metody innej klasy (rodzica). To wspomaga ponowne wykorzystanie kodu i ułatwia jego utrzymanie.
Polimorfizm — umożliwia używanie jednolitego interfejsu do pracy z obiektami różnych klas. Jest to osiągane poprzez przesłanianie metod w klasach potomnych, które są dziedziczone po rodzicach.
Abstrakcja — polega na wyodrębnianiu ogólnych cech obiektów i tworzeniu klas, które reprezentują te wspólne cechy. To pomaga uprościć skomplikowane systemy i poprawić ich zrozumiałość.
Jeśli zrozumiałeś choć połowę — świetnie. Dalej szczegółowo omówimy każdy z tych punktów.
2.2 Abstrakcja
Dobrym przykładem abstrakcji w prawdziwym życiu jest opis stanowisk w firmie czy organizacji. Nazwa stanowiska to jedno, a obowiązki każdego konkretnego stanowiska to już coś innego.
Wyobraź sobie, że projektujesz strukturę swojej przyszłej firmy. Możesz podzielić obowiązki sekretarza: „rozrzucić” je na kilka innych stanowisk. Możesz podzielić stanowisko dyrektora wykonawczego na kilka niezależnych stanowisk: dyrektor finansowy, dyrektor techniczny, dyrektor ds. marketingu, dyrektor ds. personalnych. Albo na przykład zjednoczyć stanowiska menedżera biura i rekrutera w jedno.
Z punktu widzenia programowania, abstrakcja to, powiedzmy, właściwe podzielenie programu na obiekty. Zwykle każdą dużą aplikację można przedstawić na dziesiątki sposobów w postaci współpracujących obiektów. Abstrakcja pozwala wybrać główne cechy i pominąć drugorzędne.
Abstrakcja jest jak strategia w wojskowości. Zła strategia — i żadna genialna taktyka już sytuacji nie naprawi.
2.3 Enkapsulacja
Celem enkapsulacji jest poprawa jakości interakcji rzeczy poprzez ich uproszczenie.
A najlepszym sposobem na uproszczenie czegoś jest ukrycie wszystkiego, co skomplikowane, przed zewnętrznymi spojrzeniami. Na przykład, jeśli zostaniesz umieszczony w kabinie Boeinga, nie od razu zorientujesz się, jak nim sterować:
Z drugiej strony, dla pasażerów samolotu wszystko wygląda prościej: kupujesz bilet, wsiadasz do samolotu, startujecie i lądujecie. Można z łatwością przemieścić się z kontynentu na kontynent, posiadając tylko umiejętności „kup bilet” i „wsiądź do samolotu”. Wszystkie złożoności związane z przygotowaniem samolotu do lotu, startem, lądowaniem i różnymi sytuacjami awaryjnymi są przed nami ukryte. Nie wspominając już o nawigacji satelitarnej, autopilocie i centrach kontrolnych na lotniskach. I to ułatwia nam życie.
Z punktu widzenia programowania, enkapsulacja to „ukrywanie implementacji”. Podoba mi się taka definicja. Nasza klasa może zawierać setki metod i realizować bardzo skomplikowane zachowanie w różnych sytuacjach. Ale możemy ukryć przed zewnętrznymi spojrzeniami wszystkie jej metody (poprzez otoczenie ich nazw „__” z dwóch stron), a do interakcji z innymi klasami zostawić tylko kilka metod. Wtedy wszystkie pozostałe klasy w naszym programie będą widziały w tej klasie tylko te trzy metody, i będą wywoływały właśnie je. A wszystkie złożoności będą ukryte wewnątrz klasy, jak kabina pilotów przed szczęśliwymi pasażerami.
2.4 Dziedziczenie
Dziedziczenie ma dwa aspekty: aspekt programistyczny i aspekt rzeczywistości. Z punktu widzenia programowania, dziedziczenie to specjalna relacja między dwoma klasami. Ale znacznie ciekawsze, co to jest dziedziczenie z punktu widzenia rzeczywistości.
Jeżeli potrzebowalibyśmy coś stworzyć w rzeczywistości, mielibyśmy dwa rozwiązania:
- stworzyć potrzebną rzecz od zera, poświęcając mnóstwo czasu i wysiłku;
- stworzyć potrzebną rzecz na podstawie już istniejącej.
Najbardziej optymalna strategia wygląda tak: bierzemy istniejące dobre rozwiązanie, trochę je dopracowujemy, dostosowujemy do swoich potrzeb i używamy.
Jeśli prześledzimy historię powstania człowieka, okaże się, że od momentu powstania życia na planecie minęły miliardy lat. A jeśli założyć, że człowiek powstał z małpy (na podstawie małpy), to minęło tylko kilka milionów lat. Tworzenie od zera — trwa dłużej. O wiele dłużej.
W programowaniu również istnieje możliwość tworzenia jednej klasy na podstawie innej. Nowa klasa staje się potomkiem (dziedzicem) już istniejącej. To bardzo korzystne, gdy istnieje klasa, która zawiera 80%-90% potrzebnych nam danych i metod. Po prostu ogłaszamy odpowiednią klasę rodzicem naszej nowej klasy, i wtedy w nowej klasie automatycznie pojawiają się wszystkie dane i metody klasy-rodzica. Naprawdę wygodne, prawda?
2.5 Polimorfizm
Polimorfizm — to pojęcie z dziedziny programowania. Opisuje sytuację, gdy za jednym interfejsem kryją się różne implementacje. Jeśli spróbować poszukać jego analogii w prawdziwym życiu, to jednym z takich analogii będzie proces prowadzenia samochodu.
Jeśli człowiek potrafi prowadzić ciężarówkę, można go posadzić i za kierownicą ambulansu, i za kierownicą sportowego auta. Człowiek może prowadzić samochód niezależnie od tego, jaki to pojazd, ponieważ wszystkie one mają ten sam interfejs sterowania: kierownicę, pedały i lewarek skrzyni biegów. Wewnętrzna konstrukcja pojazdów jest różna, ale wszystkie one mają ten sam interfejs sterowania.
Jeśli wrócić do programowania, polimorfizm pozwala jednolicie odwoływać się do obiektów różnych klas (zwykle mających wspólnego przodka) — rzecz, której trudno nie docenić. Jego wartość jest tym większa, im większy jest program.
OOP — to zasady. Wewnętrzne przepisy. Każdy z nich w pewnym stopniu nas ogranicza, dając w zamian duże korzyści, gdy program rozrasta się do dużych rozmiarów. Cztery zasady OOP to jak cztery nóżki krzesła. Usunąć choćby jedną, a cały system stanie się niestabilny.
GO TO FULL VERSION