Cele lekcji
Po zakończeniu tej lekcji…
- Dowiesz się, czym są funkcje, procedury i metody.
- Zrozumiesz, w jaki sposób funkcje wywołują inne funkcje.
Czym są funkcje, procedury i metody?
Te pojęcia służą do opisywania niewielkich fragmentów programów odpowiedzialnych za wykonywanie określonych funkcji,
takich jak obliczenia matematyczne, odczytywanie danych z pliku lub składanie zamówienia w witrynie internetowej. Mogą to być zarówno proste zadania, jak i skomplikowane działania. Jeśli jednak dane zadania/funkcje są złożone, należy je rozbić na mniejsze zadania/funkcje, co ułatwi odczytywanie ich kodu.
Osobiście staram się, aby żadna moja funkcja nie była dłuższa niż 15-20 wierszy. Niekiedy jednak warto tworzyć dłuższe funkcje. Niemniej łatwiej jest zrozumieć działanie funkcji, którą w całości widać na ekranie i nie trzeba jej przewijać.
Aktualnie wszystkie wymienione wcześniej nazwy są używane wymiennie. Dawniej programiści „funkcją” nazywali składnik programu wykonujący operację i zwracający wartość. Natomiast „metoda” wykonywała działanie, ale nie zwracała żadnej wartości.
W utworzonej przez nas klasie World.cs znajduje się osiem metod (bez wliczania metody konstruktora).
Metody niezwracające wartości
Pierwsze cztery metody rozpoczynają się poleceniem Populate. Spójrzmy na metodę PopulateItems.
private static void PopulateItems() { Items.Add(new Weapon(ITEM_ID_RUSTY_SWORD, "Rusty sword", "Rusty swords", 0, 5)); Items.Add(new Item(ITEM_ID_RAT_TAIL, "Rat tail", "Rat tails")); Items.Add(new Item(ITEM_ID_PIECE_OF_FUR, "Piece of fur", "Pieces of fur")); Items.Add(new Item(ITEM_ID_SNAKE_FANG, "Snake fang", "Snake fangs")); Items.Add(new Item(ITEM_ID_SNAKESKIN, "Snakeskin", "Snakeskins")); Items.Add(new Weapon(ITEM_ID_CLUB, "Club", "Clubs", 3, 10)); Items.Add(new HealingPotion(ITEM_ID_HEALING_POTION, "Healing potion", "Healing potions", 5)); Items.Add(new Item(ITEM_ID_SPIDER_FANG, "Spider fang", "Spider fangs")); Items.Add(new Item(ITEM_ID_SPIDER_SILK, "Spider silk", "Spider silks")); Items.Add(new Item(ITEM_ID_ADVENTURER_PASS, "Adventurer pass", "Adventurer passes")); }
Na początku występuje zakres private.
Private oznacza, że dana metoda może zostać uruchomiona tylko przez inny kod w obrębie tej samej klasy. Jeśli wybralibyśmy zakres public, to taką metodę można by uruchomić z poziomu innych klas. W tej metodzie nie jest to wymagane, ponieważ jest ona uruchamiania tylko raz – z poziomu klasy konstruktora.
Następnie pojawia się zakres static.
Metody zazwyczaj są uruchamiane w obiektach. Przykładowo: obiekt monster może zawierać metodę ReceiveDamage obsługującą ilość obrażeń zadanych potworowi i odejmującą tę wartość z CurrentHitPoints. Metoda wykonuje operację na obiekcie.
Jeśli chcesz uruchomić metodę bez tworzenia wystąpienia obiektu z klasy, wymagana jest metoda statyczna (static). Ta metoda znajduje się w klasie statycznej, której wystąpienia nie można utworzyć, więc wymagana jest tu deklaracja static.
Następnie mamy void.
Void oznacza, że dana metoda nie zwraca wartości, a tylko wykonuje określone zadanie. W naszym przypadku zadanie to polega na uzupełnieniu listy Items o przedmioty dostępne w świecie gry.
Na koniec została nam metoda PopulateItems.
Metodom warto nadawać nazwy, które są dla nas zrozumiałe. Ponieważ w przyszłości Ty lub inny programista możecie wprowadzać zmiany w programie, to zrozumiałe nazwy ułatwią wam stwierdzenie, do czego służy dana metoda.
Metodom zazwyczaj nadaje się nazwy w formacie czasownik-rzeczownik, czyli: co chcesz zrobić i na jakim elemencie zostanie wykonana ta operacja.
Metody zwracające wartość
Przyjrzyjmy się metodzie zwracającej informacje, np. ItemByID.
public static Item ItemByID(int id) { foreach(Item item in Items) { if(item.ID == id) { return item; } } return null; }
Tym razem zakres metody jest publiczny (public).
Tę metodę należy „wywołać” (czyli uruchomić) z poziomu innej części naszej gry, więc musi ona być oznaczona jako publiczna.
Nadal potrzebujemy określenia static (statyczna), ponieważ ta klasa nigdy nie jest obiektem.
Zamiast void mamy element Item,
ponieważ metoda będzie zwracać wartość, której typem danych będzie Item. Użytkownik również wie, że po wywołaniu ta metoda powinna zwrócić Item.
Ponadto akceptuje ona parametry, podobnie jak konstruktory w innych klasach. Niedługo przyjrzymy się uważniej tej metodzie, ale już teraz można się domyślić, że akceptuje ona numer ID i zwraca przedmiot (Item) o odpowiednim numerze ID.
Metody wywołujące inne metody
Kod konstruktora tej klasy zawiera tylko nazwy metod Populate w tej klasie, ponieważ ta metoda tylko uruchamia inne metody.
static World() { PopulateItems(); PopulateMonsters(); PopulateQuests(); PopulateLocations(); }
Po wywołaniu konstruktora uruchamia on metodę PopulateItems, a następnie metody PopulateMonsters, PopulateQuests i PopulateLocations.
Uruchamianie programu polega na kolejnym wykonywaniu wierszy kodu (o ile nie mówimy o programowaniu wielowątkowym). Wyobraźmy więc sobie, że komputer działa w następujący sposób:
- Rozpoczyna uruchamianie konstruktora World.
- Zauważa wiersz PopulateItems(); i przechodzi do metody PopulateItems.
- Wykonuje wszystkie wiersze w metodzie PopulateItems i dodaje przedmioty do listy.
- Po dojściu do końca metody PopulateItems komputer wraca do ostatniego położenia w konstruktorze World.
- Kolejny wiersz to PopulateMonsters();, więc komputer przechodzi do metody PopulateMonsters i wykonuje wszystkie zawarte w niej instrukcje.
- Po zakończeniu wykonywania metody PopulateMonsters wraca do metody World i wykonuje kolejny wiersz PopulateQuests();.
- I tak dalej.
Kod w jednej metodzie może wywołać inną metodę, która może zawierać kod wywołujący kolejną metodę, która z kolei wywołuje jeszcze jedną metodę i tak dalej…
W dużych programach takie zagnieżdżenia mogą mieć 20 i więcej poziomów. Przez to trudno wyszukuje się błędy, ponieważ programista nie jest pewny, co dzieje się w kolejnych warstwach. Pamiętaj więc, aby tworzyć jak najmniej skomplikowane programy i nie dodawać kolejnych warstw tylko dlatego, że można to robić.
Podsumowanie
Zapoznaliśmy się z podstawowymi informacjami o funkcjach, procedurach i metodach.
Te elementy są istotne, ponieważ musisz je tworzyć, aby program wykonywał funkcje. Niektóre z nich będą obsługiwać dane wprowadzane przez użytkownika, inne umożliwią poruszanie się postaci, a jeszcze inne będą odpowiadać za prowadzenie walk. Będzie to nasz mózg programu.