Jesteś tutaj
Główna > BlogV1 > Programowanie Obiektowe – czyli jak programować, aby skutecznie tworzyć realny świat?

Programowanie Obiektowe – czyli jak programować, aby skutecznie tworzyć realny świat?

W moim pierwszym artykule zachęcałem Cię do tego, żebyś zaczął zmieniać świat. Całym sobą podtrzymuje to, zanim jednak stworzysz aplikacje sterującą rynkami finansowymi na całym świecie pozwól, że przejdziemy razem przez pewne (również ciekawe!) podstawy;) zaczynamy tym samym nasz pierwszy, dwuartykułowy cykl z dziedziny Kreatywnego IT, zatytułowany – a jakże by inaczej – baza. Zakładam tutaj, że umiesz podstawy programowania strukturalnego w c++ (Jeśli jest inaczej, w materiałach znajdziesz doskonały olbrzymi tutorial). Cykl bazowy wprowadzi Cię w świat programowania obiektowego – pokażę Ci czym to jest oraz „z czym to się je”. Razem zrobimy również prosty program który z pewnością rozwieje wszelkie wątpliwości;) Do dzieła!

OOP – podstawy

Zacznijmy od podstawowej rzeczy – co to w ogóle jest OOP i po co je stosujemy? Ujmując rzecz nieformalnie, OOP (Object Oriented Programming – programowanie zorientowane obiektowo) to pewna filozofia tworzenia oprogramowania, która – w przeciwieństwie do strukturalnego – bazuje na klasach i ich obiektach. Już się tłumaczę z tego dość zawiłego zwrotu. Załóżmy ze chcemy napisać jakiegoś RPGa, dla ułatwienia weźmy lubianego powszechnie Wiedźmina, który w końcu jest naszą narodową dumą;) Cała gra może oczywiście zostać napisana w jednym pliku, w funkcji main z milionem zmiennych na początku… Nieee, oczywiście że nie może! Jak mniemam domyślasz się, ze nie dałoby się tego zrobić ze względu na monstrualnych rozmiarów bałagan jaki by powstał. Dodatkowo – przy takiej złożoności gry jaka ma Wiedźmin – nie sposób byłoby zaprojektować od strony inżynierskiej takiego kodu. Na szczęście programiści są zaradni i stworzyli… Klasy! Klasy to pewne typy struktur danych, które programista tworzy sam. Pozwala to wejść na zupełnie inny, dużo bardziej naturalny poziom. Każda klasa składa się z pól (zmiennych) oraz metod (funkcji).

Wróćmy do przykładu Wiedźmina – nie musimy już posługiwać się milionem nic nie mówiących zmiennych. Możemy stworzyć klasę ‚postać’, która będzie miała pola: życie, wytrzymałość, szybkość, imię oraz bron. Metody jakie stworzylibyśmy dla naszej klasy to: Biegnij() oraz Zaatakuj(). Wspaniale! Zauważyłeś pewnie jednak drobną nieścisłość. Przypatrzmy się typom pól: int, float, float, string i…? No właśnie, czym miałaby być bron? Stringiem który opisuje jej nazwę? A może floatem który opisuje jej atak? Na szczęście żyjemy w świecie programowania obiektowego i nie musimy się ograniczać;) Stwórzmy zatem klasę… Bron! Sadze ze tutaj sprawa jest bardzo prosta, klasa będzie zawierać jedynie dwa pola: nazwa (string) oraz atak (float).

Wszystko bardzo fajnie, ale ‚postać’ to dosyć ogólne stwierdzenie. Wiemy przecież, że w świecie Andrzeja Sapkowskiego jest bardzo dużo rodzajów postaci i ze różnią się one od siebie dosyć znacząco. Możemy zatem uszczegółowić. W tym celu skorzystamy z pewnej relacji miedzy klasami, która nazwana została ‚dziedziczeniem’. To bardzo proste – klasa pochodna(potomek) dziedziczy wszystkie pola i metody po klasie bazowej (przodek). W tym przypadku możemy stworzyć kilka klas pochodnych: krasnolud, elf, człowiek. Każda z tych klas automatycznie będzie miała życie, wytrzymałość, szybkość oraz bron. Będzie również miała metody Biegnij() oraz Zaatakuj(). Możemy jednak każdej z nich dodać cos specyficznego dla danej rasy. Np. krasnoludowi możemy dać dodatkowa metodę RozpocznijAwanture() a elfowi dodać pole kołczan. Jakie jeszcze inne klasy i związki mogłyby wystąpić w grze autorstwa CD Projekt Red? Wymieńmy pokrótce kilka: zapewne może być bron po której dziedziczy miecz, łuk oraz topór. Potwór po którym dziedziczą utopiec, przeraza, kikimora oraz troll. Na końcu możemy oczywiście stworzyć ‚Eliksir’, który zawiera w sobie inne klasy – składniki. Gdy mamy już zbudowaną strukturę naszego programu (Gry tez są rodzajem aplikacji. W dodatku jednym z fajniejszych;)), możemy przystąpić do tworzenia obiektów. Jeśli pomyślisz o klasie jako o typie zmiennych, to obiekt jest właśnie zmienną (z resztą nie trzeba traktować tego jak metaforę. Tak naprawdę jest!). Możemy więc stworzyć całą armię robiąc 1000 elementową tablicę krasnoludów. Możemy stworzyć kilka obiektów klasy ‚Krasnolud’ oraz kilka klasy ‚Człowiek’ i umieścić ich w obiekcie klasy ‚Karczma’, który to będzie elementem obiektu klasy ‚Miasto’. Prawda ze programowanie zaczyna wyglądać bardzo naturalnie, żeby nie powiedzieć „przyjaźnie”? Jestem przekonany, że w mig przyswoiłeś sobie wszystko co napisałem na górze. Jest jednak jeszcze jedna rzecz, o której koniecznie musisz wiedzieć.

Ta rzecz to hermetyczność. Wyobraźmy sobie klasę człowiek (ale w życiu realnym, nie w grze). Może ona mieć takie pola jak: wątroba, poziom krwi, serce, nerki. Nie chcielibyśmy żeby każdy mógł nam majstrować przy nerkach prawda? Właśnie dlatego w klasach zarówno pola jak i metody maja jeden z trzech modyfikatorów dostępu. Public wskazuje, że element jest dostępny publicznie i ma do niego dostęp każdy. Private – dostęp jedynie dla metod wewnątrz klasy. Protected – podobnie jak private, jednak jest dziedziczone przez klasy potomne. No dobrze, ale pewnie chciałbyś w razie potrzeby, aby do poziomu krwi miał dostęp lekarz? Od tego są specjalne metody zwane geterami oraz seterami. Getery (lub krócej – gety) wyciągają wartość danego pola zaś setery (sety) nadają określonemu polu wartość. Daje nam to bardzo ważną możliwość kontroli tego co wpływa do naszych pól. Tak więc możemy ustawić ogranicznik w seterze przeznaczonym dla poziomu krwi i nadać granice – nie można zmienić stanu pola jeśli będzie miało ono mieć w efekcie mniej niż 2.5 oraz nie wolno jeśli mielibyśmy mieć więcej niż 6 litrow. Możemy nie stworzyć getera lub setera, wtedy ograniczany możliwości tego kto chciałby majstrować później przy obiekcie. Dla przykładu – pole może być stanem konta bankowego w danym momencie. Nie chcemy raczej żeby ktoś poza nami miał do niego dostęp, nie stworzymy więc geta. Nie damy tym samym żadnej możliwości zdobycia wiedzy o tym ile pieniążków zgromadziliśmy. Znakomicie! Poznałeś już teoretyczne podstawy programowania obiektowego, czas zabrać się za aspekt praktyczny.



Tworzymy aplikację – baza sklepu

Stworzymy razem prostą aplikację do przechowywania danych o produktach oraz prostych operacji na nich. Do dzieła! Na początku wypiszmy funkcjonalności jakie będzie posiadał nasz program – nazwijmy go sklepem.

  • Przeglądanie obecnego zbioru produktów
  • Dodawanie nowych produktów do zbioru
  • Dodanie konkretnych produktów do naszego prywatnego koszyka
  • Wyświetlenie naszego koszyka

Po tym krótkim wstępie projektowym pobawmy się w inżynierię oprogramowania. Zastanówmy się jakich klas będziemy potrzebować do Sklepu. Mimo mojej miłości do wszystkiego co polskie, w tym oczywiście do języka – kod budować będę w języku angielskim i Tobie też to zalecam;)

  • Product- oczywiście najbardziej podstawowa klasa.

Pola:

  • int id
  • string name
  • Float price

Metody:

  • GetId()
  • GetName()
  • SetPrice()
  • SetId()
  • GetPrice()
  • WriteProduct()

 

  • Base – baza produktów. Wykorzystamy ją dwukrotnie. Najpierw jako ogólny zbiór, a później również jako nas osobisty koszyk.

Pola:

  • Product products[100] – 100 elementowa tablica produktów
  • String name

Metody:

  • AddProduct()
  • RemoveProduct()
  • GetName()
  • SetName()
  • WriteProducts()
  • CalculateProducts()

 

Zatem zabierzmy się za implementację! Używam do tego celu środowiska Visual Studio 2013 i Tobie też to zalecam. Po utworzeniu projektu (który nazwiemy „ShopBase”) oraz pliku „main.cpp” z funkcją main() zabierzmy się za utworzenie pierwszej klasy! Klikamy „Project->Add Class”, a następnie „Add”. W pole „Class Name” wpisujemy „Product” i klikamy „Finish”. Brawo! Twoja pierwsza klasa została właśnie stworzona! Jak widzisz środowisko wygenerowało Ci dwa pliki: jedno z rozszerzeniem „.h” i jedno z rozszerzeniem „.cpp”. Pierwszy z nich to tzw. header – plik nagłówkowy, w którym będziemy jedynie definiować pola i metody, w drugim zaś te same pola i metody będziemy implementować. Dopisz odpowiednie miejsca, aby cała klasa wyglądała następująco:

Jak widzisz zaimplementowaliśmy wszystkie pola oraz metody które zaplanowaliśmy. Ale zaraz, co to za dziwne metody na początku i na końcu?! Już tłumaczę. Gdy tworzymy klasę automatycznie tworzą nam się: konstruktor oraz destruktor. Pierwszy z nich to metoda, która wywołana będzie zawsze podczas tworzenia obiektu, zaś destruktor – tak, zgadłeś! Podczas usuwania 😉 Mamy jednak dość specyficzną konstrukcję. Pierwszy z konstruktorów jako argument przyjmuje id, name oraz string – czyli nasze pola prywatne, które zaraz też wypełniamy. Gdy jednak użytkownik nie poda żadnych argumentów stosujemy konstruktor domyślny – w naszym przypadku tworzymy bardzo specyficzny obiekt o „nierealnych danych” takich jak -1 jako id. Jeśli któryś z produktów będzie miał to id będziemy go traktować jako obiekt który nie istnieje i dopiero jest „do stworzenia”. Reszta metod jak mniemam nie wymaga komentarza (Gety i Sety pisze się podobnie, więc zostawiłem jedynie po jednym dla przykładu), jednak gdybyś miał z którąkolwiek z nich problem nie wahaj się i śmiało pisz na mojego maila 😉

Sądzę, że większość jest jasna. Jestem jednak winien komentarz w jednym z moich ruchów. Gdy spojrzysz na drugą linijkę pól prywatnych zobaczysz tablicę 100 elementową produktów. Musisz wiedzieć, że zastosowałem takie rozwiązanie TYLKO ze względu na łatwość implementacji. Trzeba jasno powiedzieć, że jest ono brzydkie i w następnym artykule przejdziemy do bardziej eleganckich i nowoczesnych rozwiązań!

Z powodu oszczędności miejsca usunąłem stąd get’y i set’y oraz destruktor. W konstruktorze ustawiamy „lastId” na 0 – będzie to nasz licznik dzięki któremu będziemy nadawali kolejne id. W AddProduct() przebiegamy po tablicy produktów i jeśli jest „wolne” miejsce (id == -1) to wstawiamy tam nasz produkt z id o 1 większym od ostatniego oddanego produktu. W RemoveProduct() wykorzystujemy konstruktor domyślny Product i wybrany rekord tablicy produktów czynimy „pustym”. WriteProducts() przechodzi tradycyjnie po tablicy i wypisuje kolejne elementy. Finalnie FindProduct() – wyszukujemy w tablicy produkt o podanym id i zwracamy go.

Znakomicie! Udało nam się zrobić to co najważniejsze – klasy. Teraz należy napisać tylko interfejs do nich. I tu czeka na Ciebie wyzwanie – ja wstawię „brzydki” bez komentarza, a Ty stwórz jego lepszą wersję i wyślij do mnie. Oczywiście najlepiej, gdyby była to wersja obiektowa!

Efekt końcowy aplikacji.
Efekt końcowy aplikacji.

Co dalej?

Brawo! Stworzyłeś swój pierwszy program do obsługi sklepowej bazy produktów 😉 Przy tej okazji dowiedziałeś się czym są klasy, metody, pola, hermetyzacja, konstruktory, destruktory oraz najważniejsze – po co my to wszystko stosujemy? Rozumiem oczywiście, że to dużo nowych informacji i jeszcze nie wszystko musi być jasne. Spokojnie! Jest czas, tylko heros zrozumie zawsze za pierwszym razem. Jeśli masz jakiekolwiek pytania pisz śmiało na mojego maila. Zapraszam do materiałów, gdzie znajdziesz również pełny projekt do pobrania. Zdaję sobie sprawę, że niektóre rozwiązania, które zastosowałem są „brzydkie”. Wobec tego zachęcam Cię… do poprawy ich! Popraw i przyślij mi rozwiązanie, a ja z przyjemnością je przejrzę. Miłego kodowania!

Skoro dotarłeś do końca – zostańmy w kontakcie na dłużej

Jeśli dotarłeś aż tutaj, to znaczy że jesteś człowiekiem innym niż większość. To znaczy, że nie wystarczają Ci skrótowce, że prawdopodobnie wymagasz od siebie nieco więcej niż przeciętnie. Pozostańmy zatem w kontakcie – zapisz się na Newsletter Wolnego Człowieka i pomóż mi tworzyć coraz lepsze treści! Jeśli zdecydujesz się wpisać – obiecuję zero spamu. Raz w tygodniu będziesz dostawał maila z podsumowaniem tego co zrobiłem na blogu.

Marek Czuma
Autor Bloga Republikańskiego. Chrześcijanin, Polak, Łodzianin. Wierzy w ludzi i ich możliwości, kocha pomagać innym. Uważa, że człowiek wolny kształtuje siebie poprzez własne wybory oraz pracę. Poza tym fan Wiedźmina i CD Projektu - zarówno na giełdzie, jak i w działaniu.

Dodaj komentarz

Top