
Programowanie obiektowe (OOP) polega na organizowaniu i upraszczaniu elementów programu w celu optymalizacji struktur kodu programu – przy użyciu obiektów, metod i właściwości.
Opisany w artykule przykładowy projekt został przygotowany przy użyciu zintegrowanego środowiska deweloperskiego (IDE) firmy Bedrock Automation. Jest ono dostępne do pobrania za darmo ze strony producenta.
Kod źródłowy przykładowego projektu można pobrać ze strony firmy Mitek Automation.
Najnowsza wersja normy IEC-61131-3 (PN-EN 61131-3), znanej powszechnie w środowisku automatyków, zawiera język programowania obiektowego (Object-Oriented Programming – OOP). Chociaż OPP jest często kojarzony z poważnie brzmiącą terminologią, to w rzeczywistości polega na zwykłym organizowaniu i upraszczaniu. Organizowanie oznacza tu sposób, w jaki elementy programu są grupowane i jak wykorzystywane są mechanizmy grupowania. Dobrze zorganizowane programy są bardziej intuicyjne, a praca z nimi jest ułatwiona. Właściwości programowania OOP zostały zaprojektowane w celu promowania i ułatwiania tworzenia zaawansowanych projektów organizacyjnych. Upraszczanie oznacza więc w tym przypadku uproszczony interfejs projektu programowego, który jest prezentowany w świecie zewnętrznym. Pod tą powierzchnią w programie przechowywane są złożone szczegóły, funkcje, wraz z samym obiektem.
Czym są obiekty?
W programowaniu OOP obiekt łączy związane z nim funkcje i dane, na których one operują, w jedną odrębną całość, która modeluje stan i zachowanie urządzeń, procesów i innych elementów, urządzeń świata zewnętrznego. W normie IEC–61131-3 obiekty są implementowane jako bloki funkcyjne o pewnych dodatkowych możliwościach. Takie bloki funkcyjne mogą definiować metody i właściwości dla dalszego podziału kodu programu i rozbudowy interfejsów. Metody i właściwości mogą być implementowane przy użyciu dowolnego języka z opisanych w normie IEC-61131-3. Wybór języka jest dokonywany metodą indywidualną lub na podstawie właściwości, co ułatwia użycie najlepiej dopasowanego języka programowania sterowników, zależnie od okoliczności.
Przedstawiony w tekście przykładowy projekt zawiera blok funkcyjny, który implementuje prosty licznik up/down (liczący w górę i w dół), i jest zdefiniowany tak, jak pokazano na rys. 1. Termin „klasa”, używany w innych językach OOP, jest synonimem „bloku funkcyjnego”. Obydwa terminy odnoszą się do definicji, które muszą zostać skonkretyzowane w programowaniu przed ich wykorzystaniem. Elementy klas lub bloków funkcyjnych są określane jako „obiekty”.

Definiowanie metod
Metody są funkcjami, które mają dostęp do definiowania danych wewnętrznych i parametrów bloku funkcyjnego. Mogą one także mieć parametry wejścia i wyjścia oraz wartości zwrotne, tak jak zwykłe funkcje.
Metodę można zdefiniować przy użyciu języka drabinkowego (Relay Ladder) jako języka implementacji. Gdy parametr wejściowy jest prawdą (TRUE), to wartość licznika zaczyna wzrastać, aż do osiągnięcia wartości maksymalnej. Parametry PMaxCount (maksymalna wartość licznika) i Count (bieżąca wartość licznika) są definiowane w głównej strukturze (main body) bloku funkcyjnego. Ponieważ metody mają dostęp do danych i parametrów bloku funkcyjnego, to PMaxCount i Count mogą być z nich pobrane i wykorzystane w metodzie.
Wartość zwrotna jest zapisywana jako CountUp (zliczanie w górę), która jest nazwą samej metody.
Zmienna NotMax (nie maksymalna) jest definiowana w metodzie i umieszczana na stosie wywołań (ang. call stack) metody. Oznacza to, że wartość z poprzedniego wykonania nie jest utrzymywana. Zmienne zdefiniowane w głównej strukturze bloku funkcyjnego są umieszczane w pamięci i utrzymują swoje wartości od wykonania do wykonania.
Druga z metod, która zmniejsza wartość licznika, jest definiowana przykładowo z wykorzystaniem języka strukturalnego (Structured Text – ST) jako języka implementacji. Gdy parametrem wejściowym jest TRUE, to wartość licznika jest zmniejszana, aż osiągnie wartość zerową. Count jest parametrem wyjściowym bloku funkcyjnego, zaś wartość zwrotna jest zapisywana jako CountDn (zliczanie w dół) nazwa metody. Ta metoda daje łatwy i wygodny sposób organizowania programu poprzez dzielenie go na mniejsze, łatwiejsze do zarządzania elementy. Ponadto jest ona zaprojektowana tak, aby łatwo można było mieszać i dopasowywać różne języki programowania.
Bardzo prosto wywołuje się te metody z poziomu głównej struktury – korpusu (body) bloku funkcyjnego, jak pokazano na rys. 2. Ponieważ metody te są zdefiniowane przy użyciu słowa kluczowego „PRIVATE” (prywatny), to mogą one być wywoływane w granicach samego bloku funkcyjnego. Metody zdefiniowane przy użyciu słowa kluczowego „PUBLIC” (publiczny) mogą być także wywoływane zewnętrznie.
Definiowane właściwości
Właściwości są funkcjami, które zachowują się jak zmienne i mogą być użyte w wyrażeniach w taki sam sposób jak zmienne. Zamiast przywiązania do konkretnej lokalizacji pamięci, właściwość jest związana ze swoimi funkcjami get() i set(). Gdy dane są odczytywane z właściwości, to wykonywana jest jej funkcja get() [uzyskaj]. Gdy dane są zapisywane do właściwości, to wykonywana jest jej funkcja set() [ustaw], jak pokazano na przykładzie w lewej kolumnie.
Słowa kluczowe „PUBLIC” i „PRIVATE” mogą być także użyte do kontroli dostępu do własności. „PRIVATE” oznacza, że właściwość może być użyta tylko wewnętrznie w granicach definiującego ją bloku funkcyjnego. Jednak słowa kluczowe „PUBLIC” i „PRIVATE” mogą być także użyte z definicją funkcji get() i set(). Umożliwia to odczyt zewnętrzny i zapis wewnętrzny właściwości.
W swojej najbardziej podstawowej formie właściwości zapisują dane do zmiennych wewnętrznych i odczytują z nich dane. Ich dodatkowe możliwości mogą być wykorzystane do walidacji wartości danych lub wykonania innych operacji. Na przykład do programu może być dodana właściwość MaxCount. Pozwala to na ustawienie maksymalnej wartości licznika jako specyficznej wartości oraz odczytanie jego wartości bieżącej. Dane przepływają pomiędzy funkcjami set() i get() za pomocą nazwy właściwości MaxCount tak, jakby były one zmiennymi. Funkcja get() zwraca wartość zmiennej bloku funkcyjnego PMaxCount. Funkcja set() waliduje wartość wejściową poprzez zapewnienie, że jest to liczba dodatnia przed zapisaniem wyniku do PMaxCount.
W następnej części analizowanego przykładu do projektu zostaje dodana właściwość Reset (resetowanie, kasowanie) przy użyciu języka drabinkowego, jak pokazano na rys. 3. Właściwość Reset nie ma swojej własnej zmiennej, która byłaby odczytywana i zapisywana. Gdy zapisywana jest wartość TRUE, to wykonywana jest operacja resetowania. Gdy odczytywana jest właściwość, to wyrażenie jest szacowane i zwracany jest wynik.
Warto zwrócić uwagę na sposób, w jaki struktura i organizacja projektu są odzwierciedlone w drzewie struktury organizacyjnej projektu. Każdy program, blok funkcyjny, metoda i właściwość w projekcie są reprezentowane przez węzeł. Podwójne kliknięcie na węźle otworzy je, tak jak zakładkę na stronie dokumentu w oknie głównym. Zakładki mogą być odłączone i wyświetlone jako osobne okna. Funkcje get() i set() są odłączone, tak więc obydwie mogą być wyświetlone wraz z definicjami właściwości.


Optymalizacja elementów programu za pomocą OOP
O programowaniu obiektowym można oczywiście napisać znacznie więcej, ale wszystko sprowadza się do jego podstawowego celu, jakim jest organizowanie elementów programu w optymalny sposób. Obiekty, metody i właściwości są podstawowymi środkami osiągania tego celu, dlatego najważniejsze jest zrozumienie i opanowanie tej koncepcji i przedstawionych w artykule elementów organizacji struktur takich programów.
Przygotowania do programowania obiektowego należy rozpocząć zatem od małych kroków w celu nabycia umiejętności organizowania najpierw konwencjonalnych programów, natomiast na projekty korzystające z obiektów przyjdzie czas później. Zaznajomienie się z wykorzystaniem technik opisanych w artykule ułatwi wyobrażenie sobie wszystkich pozostałych możliwości OOP. Warto je poznać i wypróbować.
Richard Jafrate jest założycielem firmy Mitek Automation. Opracowanie tekstu: Chris Vavra, redaktor produkcji w CFE Media.