Programowanie obiektowe #0 – wprowadzenie

Ucząc się języków programowania zapewne nieraz spotkałeś się z terminem „obiektowość”. Jest to jeden z najpopularniejszych paradygmatów programowania. Obecnie znajomość języków obiektowych jest jednym z podstawowych wymagań na rynku pracy IT. W związku z tym mamy przyjemność przedstawić Wam pierwszy wpis z serii o programowaniu obiektowym. Omówimy dzisiaj wspólnie czym jest programowanie obiektowe, a także wprowadzimy podstawowe pojęcia.

Obiektowość jako paradygmat programowania

Zacznijmy od wyjaśnienia czym jest paradygmat programowania. W uproszczeniu możemy nazwać go sposobem zapisu i organizacji działań w danym programie lub algorytmie. Dowolny algorytm lub program możemy zapisać w różny sposób, np. strukturalny, proceduralny, czy właśnie obiektowy. Każdy język programowania bazuje na co najmniej jednym paradygmacie.

Pierwsze języki programowania, jak Fortran, czy COBOL, wspierały imperatywny paradygmat programowania. Paradygmat ten polega na zapisie sekwencji instrukcji, które bezpośrednio zmieniają stan programu. Instrukcje te można porównać z trybem rozkazującym, gdy np. współlokator żąda abyśmy wyrzucili śmieci. Podobnie jest w programowaniu imperatywnym, gdzie wydajemy odpowiednie żądania komputerowi.  

Z czasem pojawiły się również języki proceduralne i funkcyjne, jednak złożoność algorytmów nieustannie rosła, wobec czego potrzebne były wydajniejsze i lepiej zorganizowane rozwiązania. To dało początek językowi Simula – pierwszemu językowi obiektowemu, matce współczesnej obiektowości. Dlaczego uznaje się go jako pierwszy język obiektowy? To właśnie w nim po raz pierwszy wprowadzone zostały obiekty i klasy, czyli podstawowe budulce programu w języku obiektowym.

Obiekt i klasa

Obiekt jest najbardziej podstawowym elementem programowania obiektowego. Każdy obiekt zawiera zdefiniowany stan, pola (jego właściwości) oraz metody (jego zachowanie). Warto tu zaznaczyć, że cechą charakterystyczną każdego obiektu jest jego unikalność. Rzućmy okiem na ten prosty przykład:

Stworzyliśmy dwa obiekty typu tekstowego a i b. Pomimo że oba obiekty przyjmują tę samą wartość, to nadal są to różne obiekty, co czyni je unikalnymi w danym obszarze aplikacji. Wykonanie jakiejkolwiek operacji na obiekcie tyczy się tylko i wyłącznie danego obiektu.

Klasy to definicje formatu danych. Pozwalają one na na stworzenie dowolnego typu obiektu, z określonymi przez nas funkcjami i własnościami. Po zdefiniowaniu klasy możemy tworzyć jej instancje, które są niczym innym jak obiektami.

Żeby lepiej zobrazować czym jest klasa i jej instancje przejdźmy do przykładu. Wyobraź sobie, że jesteś producentem samochodów. Dany model samochodu możemy postrzegać jako klasę: każdy z nich posiada bowiem swoją własną strukturę, nazwę, kształt i inne właściwości oraz zachowania. Produkując samochody opierasz się właśnie na takiej klasie, a każdy wyprodukowany samochód możemy nazwać jej instancją.

Spójrzmy na przykładową klasę:

Worker.h

Worker.cpp

Stworzyliśmy właśnie klasę Worker, która posiada metodę hello(), a także pole salary. W pliku źródłowym klasy zainicjalizowaliśmy zmienną, a także zaimplementowaliśmy funkcję. Oczywiście jest to możliwe do zrobienia w jej pliku nagłówkowym, ale poprawniej i czytelniej jest implementować metody i pola w pliku źródłowym. Zauważ, że elementy klasy znajdują się pod słowem kluczowym public, co oznacza, że są one widoczne dla każdego, kto ma dostęp do instancji obiektu tej klasy. Wrócimy do tego tematu za chwilę.

Teraz możemy wykorzystać naszą nowo utworzoną klasę w pliku głównym programu:

Tworząc nową instancję naszej klasy Worker mamy dostęp do metody hello() i pola salary. Zauważ, że pole to możemy swobodnie modyfikować. Zwróć również uwagę, iż wywołując funkcję i odczytując pole wykorzystaliśmy wskaźnik na adres obiektu, a nie jego wartość. Różnica pomiędzy wykorzystywaniem referencji obiektu, a jego wartości została w prosty sposób przedstawiona w tym artykule.

Programowanie obiektowe – filary

Programowanie obiektowe jednak nie opiera się jedynie na klasach i obiektach. Istnieją pewne zasady, których należy przestrzegać. Zasady te możemy nazwać filarami, na których opiera się obiektowość. Zaliczamy do nich:

Każdy z filarów omówimy szczegółowo wraz z przykładami w następnych, dedykowanych im wpisach z serii. Grzechem by było jednak z naszej strony nie wspomnieć o nich co nieco w dzisiejszym poście:

Dziedziczenie

Wyobraź sobie, że tworzysz reprezentację firmy posługując się językiem obiektowym. Zatrudnia ona hydraulików, mechaników, masażystów i kaskaderów (taka firma od wszystkiego 🙂 ). Logiczne jest, że dla każdego z tych pracowników stworzyłbyś oddzielne klasy, bo przecież masażysta nie będzie używać metalowego kolanka przy swojej pracy, a kaskader nie umie wykryć pękniętej uszczelki pod głowicą. Są jednak informacje, które charakteryzują każdego z nich: imię, nazwisko, PESEL, pensja itd. Trzeba by więc dla każdego z nich osobno tworzyć te same pola, co po 1. jest niewygodne, a po 2. niewydajne.

Z pomocą przychodzi dziedziczenie, które pozwala na tworzenie podklas, które dziedziczą właściwości i metody po innej klasie. Dzięki temu możesz stworzyć klasę Pracownik, a w niej zawrzeć wymagane dla każdego pracownika pola. Następnie możesz stworzyć osobno klasy Hydraulik, Mechanik, Masazysta, Kaskader, które rozszerzać będą klasę Pracownik, jednocześnie posiadając swoje własne, unikalne pola i funkcje. Dziedziczenie pozwala wiec na tworzenie ogólnych klas, na których mogą bazować klasy bardziej złożone, a także umożliwia współdzielenie funkcjonalności pomiędzy tymi klasami.

Polimorfizm

Mamy wiec podstawową reprezentację naszej hipotetycznej firmy. Co pewien okres powinniśmy wezwać pracownika, aby zdał nam sprawozdanie ze swojej pracy. Jak wiadomo każdy pracownik wykonuje inną pracę, więc nie możemy zawrzeć sprawozdania w klasie Pracownik. Musielibyśmy więc za każdym razem sprawdzać, czy Pracownik jest Hydraulikiem, jeżeli tak, to wywołać funkcję Hydraulik.sprawozdanie(), jeżeli nie, to sprawdzić, czy jest Mechanikiem itd. Jak widzisz byłoby to dosyć skomplikowane i niewygodne. Tutaj do akcji wkracza polimorfizm: pozwala on na zdefiniowanie metody w klasie Pracownik, a następnie na implementację jej w klasach dziedziczących. Dzięki temu każda z podklas będzie posiadała tą samą funkcję, ale o innym działaniu. My zaś nie musimy znać dokładnego typu klasy – wystarczy, że wiemy iż jest ona Pracownikiem, więc możemy prosto wywołać funkcję Pracownik.sprawozdanie(). Polimorfizm daje nam więc możliwość wyabstrahowania wyrażeń od konkretnych klas lub typów.

Abstrakcja

Każda z naszych klas z powyższego przykładu dziedziczy metodę sprawozdanie() po klasie Pracownik. Faktem jest, że gdy jako pracodawca wywołujemy tą metodę, to nie obchodzi nas w jaki sposób zostanie ona wykonana, ale za to interesuje nas wynik jej działania. Na tym właśnie polega abstrakcja – wszelkie działania mają być wykonywane bez ujawniania sposobu implementacji danych cech. Dzięki temu nasze klasy są bardziej elastyczne i łatwiejsze do rozbudowania.  

grupa wsparcia matura z informatyki

Hermetyzacja

Czy chciałbyś aby każdy kogo znasz mógł zmienić Twoje imię w dowodzie osobistym? Zapewne, zdecydowanie nie. Podobnie jest z pracownikami w naszej firmie – każdy może znać imię lub nazwisko pracownika, jednak nikt nie powinien móc go zmienić. Przed tym chroni nas właśnie hermetyzacja, zwana inaczej enkapsulacją.

Pozwala ona na dosłowne zamknięcie odpowiednich elementów klasy w „kapsule”, dostępnej jedynie dla określonych obiektów. Dzięki temu obiekt nie może zmieniać stanu wewnętrznego innego obiektu w niekontrolowany sposób. Przykładem zastosowania hermetyzacji jest zastąpienie publicznych pól, publicznymi metodami zwracającymi wartość prywatnych pól. Dzięki temu wszyscy spoza klasy danego pracownika będą widzieli jego imię i nazwisko, nie mając jednocześnie możliwości jego zmiany.

Podsumowanie

W dzisiejszym wpisie dowiedziałeś się czym jest programowanie obiektowe, a także czym jest klasa i obiekt – jego podstawowe elementy. Omówiliśmy również krótko każdy z filarów, na których ona bazuje. W następnej lekcji zajmiemy się dokładniej dziedziczeniem. Znajomość obiektowości może być przydatna na maturze z informatyki. Możesz sprawdzić listę rzeczy, których warto do niej powtórzyć w tym wpisie.

You Might Also Like
Dodaj komentarz

icon