5. Funkcje własne.

5.1. Czym są funkcje własne

W poprzednich 4 lekcjach uczyliśmy się pisać proste programy, które jeszcze nie były zbyt rozbudowane. Z czasem, kiedy zaczniesz tworzyć coraz to bardziej skomplikowane programy, pojawi się naturalna potrzeba uporządkowania kodu i poprawienie jego czytelności. To tak jak w innych sprawach. Jeśli na biurku panuje bałagan to znalezienie potrzebnego dokumentu wymaga więcej czasu i wysiłku. Nawet jeśli dbasz o porządek w papierach, ale jest ich za dużo, to lepiej byłoby poukładać je w segregatory i odłożyć gdzieś na półkę. Masz wtedy pod ręką tylko to co jest ci potrzebne do realizacji bieżących zadań. Dopiero w momencie, gdy potrzebujesz konkretne dokumenty, możesz wziąć z półki odpowiednie segregatory, położyć obok siebie i nadal wygodnie sobie pracować. No ba, nawet w segregatorach dokumenty możesz poukładać tak jak ci będzie wygodniej, opisać je tak, że już po samej nazwie będziesz wiedział o zawartości segregatora i do czego on służy. Można powiedzieć, że tworzysz własne segregatory i dopiero w momencie załatwiania konkretnego zadania pracujesz z potrzebnym ci segregatorem.

Podobnie można poukładać kod programu. Jeśli spodziewamy się, że może on być duży lub w wielu miejscach będzie zawierał identyczne elementy, to warto napisać go z użyciem funkcji własnych. Wiele języków programowania pozwala zastosować tę technikę programowania i MQL4 nie jest tu wyjątkiem. Zanim przejdziemy do technicznej strony realizacji funkcji własnych, chciałbym najpierw pokazać w jakiej sytuacji ich stosowanie ma sens.

Załóżmy, że chcemy przygotować skrypt do obróbki 10 różnych sytuacji, przy tym w 6 z nich powinien on postąpić w jeden sposób (A), a w pozostałych 4 w inny sposób (B). Zobrazujmy schemat takiego kodu na poniższym rysunku 1.

Rys. 1. Schemat stosowania funkcji własnych.


Na tym schemacie szare linie symbolizują linie kodu źródłowego. Określenie sytuacji realizowane są za pomocą operatora if, gdzie sytuacje 1, 2, 4, 6, 7 i 10 są obrabiane w sposób A (zielony kolor), a sytuacje 3, 5, 8 i 9 w sposób B (niebieski kolor). Jaki wniosek może się nasunąć przy pierwszym spojrzeniu na ten schemat? Widać, że ta część kodu, która odpowiada za Działanie A, została zapisana 6 razy, a za Działanie B - 4 razy. Z punktu widzenia realizacji swoich zadań ten program działa bez zarzutu.

Wyobraźmy sobie, że całkowity kod programu składa się z kilku tysięcy linijek, a każde z działań A i B ma po 100 linijek. Po jakimś czasie po napisaniu programu przychodzisz do wniosku, że fajnie było by trochę zmodyfikować działanie A. W tym przypadku otwiera się przed tobą perspektywa grzebania w 6 miejscach, gdzie należy wprowadzić poprawki. Ok, udało się. Po pewnym czasie zauważasz, że sytuacja 7 nie jest obrabiana jak należy. Wracasz do kodu i okazuje się, że ta część zawiera błąd. Ok, poprawiasz, ale przy okazji warto było by sprawdzić i pozostałe kawałki kodu, gdzie to Działanie A jest stosowane. Jest to męczące, nieprawdaż? A co jeśli to działanie zostało by zastosowane nie w 6, a np. w 1000 miejscach? Jak tu nie złapać się za głowę .

Co jeśli po jakimś czasie znowu trzeba będzie coś poprawić w Działaniu A. Czy to znaczy, że za każdym razem jesteśmy skazani na taką pracę? A czy można było by tylko raz opisać to działanie, a w odpowiednich miejscach w jakiś magiczny sposób go aktywować? Tak, jest to możliwe. Działanie A opiszemy osobno jako funkcję własną, a w odpowiednich miejscach kodu będziemy ją wywoływać (rys. 2).

Rys. 2. Schemat stosowania funkcji własnych.


Tutaj poza granicami OnStart() umieściliśmy naszą funkcję o nazwie Funkcja_A, gdzie opisaliśmy pożądane Działanie A. Odpowiednie operatory if mają teraz tylko jedną linijkę kodu, która odpowiada za wywołanie tej funkcji. W chwili, kiedy taki program napotka się na sytuację 1, 2, 4, 6, 7 lub 10 wywoła on do działania naszą funkcję własną (zielone strzałki). Teraz zamiast tego, aby 6 razy powtarzać 100 linijek tej samej części kodu, zapisaliśmy je tylko 1 raz, co zdecydowanie skróciło kod oraz poprawiło jego czytelność. Przy ewentualnych poprawkach nie musimy już łazić w całym kodzie, wystarczy tylko w jednym miejscu nanieść zmiany i mieć całkowitą pewność, że Działanie A zostanie w jednakowy sposób zrealizowane wszędzie tam, gdzie Funkcja_A jest używana. Jakaż to jest oszczędność czasu i włosów na głowie!

Być może w tym momencie intuicyjnie czujesz, że coś podobnego można zrobić i w pozostałych sytuacjach 3, 5, 8 i 9 dla Działania B. Tak, dla nich też można przygotować swoją funkcję Funkcja_B i w odpowiednich miejscach zapisać tylko jedną linijkę kodu, odpowiadającą za jej wywołanie (rys. 3).

Rys. 3. Schemat stosowania funkcji własnych.


Myślę, że poczułeś moc funkcji własnych! Można je scharakteryzować jako swoiste podprogramy, które możemy wielokrotnie wykorzystywać w naszych programach. Jeśli planujemy napisać jakiś duży program, np. automatyczną strategię handlową do zarabiania milionów, możemy najpierw w głowie rozbić program na mniejsze elementy. Następnie, dla każdego z nich przygotować funkcję własną i z takich klocków ułożyć program.

Co jeszcze możemy zyskać, używając funkcje własne? Jeśli masz kolegów, którzy też interesują się programowaniem na MQL4 i postanowiliście razem napisać program, to możecie podzielić się miedzy sobą zadaniami. Np. ja piszę właściwy kod programu, jeden kolega funkcję dla Działania A, a drugi funkcję dla Działania B. Może też być tak, że jakiś inny programista niezależnie od nas wcześniej wpadł na pomysł z Działaniem A, napisał funkcję i udostępnił ją w internecie. Możemy wziąć taki gotowiec i dopasować go do naszych potrzeb. Pewne gotowe funkcje możesz znaleźć na mojej stronie w zakładce BAZA KODÓW lub na forum MQL4 w rozdziale Code Base. Można też w osobnym pliku przygotować bibliotekę własnych funkcji i ten plik dołączyć do programu. O realizacji tej możliwości można poczytać w rozdzialach 5.13 - 5.16.

W następnym rozdziale pokażę jak prawidłowo wygląda przygotowanie funkcji własnych i ich wywołanie.