Dokumentace

Objektové programování (OOP)

Idekit Studio dovoluje používat některé z objektových vlastností používaných v jazycích jako je Java, .NET nebo C++. Základním typem pro využívání těchto vlastností je funkční blok. Je možné využívat následující konstrukty:

  • Zapouzdření
  • Metody, včetně virtuálních metod
  • Odkazovat se na předka (SUPER)
  • Hierarchické struktury a dědění
  • Definovat a implementovat rozhraní (interfaces)
  • Polymorfismus

Všechny zvyklosti (RETAIN, INPUT, OUTPUT, INOUT, ...) jsou shodné s klasickým použitím funkčního bloku.

Motivační příklad - counter

Následující příklad ukazuje implementaci jednoduchého čítače, který má maximum, minimum, možnost čítat nahoru nebo dolu a umí vracet aktuálně načítanou hodnotu:

FUNCTION_BLOCK CCounter
VAR
m_iCurrentValue: INT;
m_bCountUp: BOOL:=TRUE;
END_VAR

VAR
m_iUpperLimit: INT:=+10000;
m_iLowerLimit: INT:=-10000;
END_VAR

METHOD GetCount : INT
GetCount := m_iCurrentValue;
END_METHOD

METHOD Count
IF (m_bCountUp AND m_iCurrentValuem_iLowerLimit) THEN
m_iCurrentValue:= m_iCurrentValue-1;
END_IF;
END_METHOD

METHOD SetDirection
VAR_INPUT
bCountUp: BOOL;
END_VAR

m_bCountUp:=bCountUp;
END_METHOD

END_FUNCTION_BLOCK

Použití takto definovaného bloku je v rámci deklarace stejné jako u jakéhokoliv jiného bloku, včetně explicitní inicializace. Jednotlivé metody se pak volají následujícím způsobem:

PROGRAM main
VAR
counter1 : CCounter;
counter2 : CCounter := (m_iUpperLimit := 15000, m_iLowerLimit := -10);
current_value : int;
END_VAR

counter1.SetDirection(bCountUp := true);

counter1.Count();

current_value := counter1.GetCount();

counter2.Count();
END_PROGRAM

Metody funkčního bloku

Koncept metod v Idekit Studio je stejný jako u jiných objektově orientovaných jazyků. Metody definují operace v rámci jednotlivých instancí funkčního bloku a operují nad daty dostupnými instanci funkčního bloku.

Deklarace metody je uzavřena mezi klíčovými slovy METHOD a END_METHOD.

Metody lze přirovnat k funkcím. Stejným způsobem se jim definuje jméno, parametry (vstupní, výstupní, lokální) a jejich návratová hodnota. Kromě jejich vlastních parametrů mohou pracovat nad společnými daty funkčního bloku.

V jednom funkčním bloku může být více metod a metody mohou volat další metody.

V současné verzi neexistuje podpora pro práci s metodami v grafických jazycích. Je možné je využívat pouze v jazyku ST. Implementace metod v Idekit Studio má podporu pro EN a ENO.

Dědičnost

Koncept dědičnosti v Idekit Studio je stejný jako u jiných objektově orientovaných jazyků. Lze definovat hierarchii funkčních bloků, kde zpravidla předek představuje obecnější strukturu a potomek nějakou konkretizaci. Idekit Studio nepodporuje vícenásobnou dědičnost. Podporuje však možnost implementovat více rozhraní (interfaces). Viz dále. Hierarchický vztah se definuje klíčovým slovem EXTENDS.

Př.:

FUNCTION_BLOCK Circle EXTENDS GeomShape.

Potomek (odděděný funkční blok) má k dispozici všechny proměnné a metody funkčního bloku, ze které dědí. K této funkčnosti může přidávat další metody a data.

Virtuální metody

Virtuální metody jsou takové metody, kterým je možné v hierarchii funkčních bloků měnit implementaci. Pokud se metoda zavolá na instanci předka, bude zavolána odpovídající implementace potomka. Například v hierarchii máme základní funkční blok GeometryShape, který definuje metodu "Area" na výpočet obsahu geometrického obrazce.

Virtuální metoda musí být označena klíčovým slovem VIRTUAL a stejně označené metody v potomcích musí toto slovo uvádět také. Není možné změnit typ metody. "Virtuálnost" musí odpovídat předkovi, a to až na úroveň první deklarace.

Jako příklad uvidíme konkrétní hierarchii geometrických obrazců s obdélníkem a kruhem a u nich implementaci odpovídajícího matematického vzorce.

FUNCTION_BLOCK GeomShape

(* abstracktni metoda predka *)
METHOD VIRTUAL Area : REAL
END_METHOD;

END_FUNCTION_BLOCK

FUNCTION_BLOCK Rectangle EXTENDS GeomShape
VAR_INPUT
x, y : real;
END_VAR

(* konkretni implementace potomka *)
METHOD VIRTUAL Area : REAL
Area := x * y;
END_METHOD;

END_FUNCTION_BLOCK

FUNCTION_BLOCK Circle EXTENDS GeomShape
VAR_INPUT
radius : real;
END_VAR

(* konkretni implementace potomka *)
METHOD VIRTUAL Area : REAL
Area := 3.14 * radius * radius;
END_METHOD;

END_FUNCTION_BLOCK

Využití je pak možné následovné:

PROGRAM geom_shapes
VAR
rect1 : Rectangle := (x := 10, y := 20);
circle1 : Circle := (radius := 10);

shape : REF_TO GeomShape;

rect_area, circle_area : REAL;
END_VAR

(* obecny predek, kteremu muzeme priradit referenci na jakehokoliv potomka *)
shape := REF rect1;

(* shape nyni predstavuje Rectangle -> spocita obsah obdelniku *)
(* rect_area bude po provedeni mit hodnotu 200 *)
rect_area := shape.Area();

shape := REF circle1;

(* shape nyni predstavuje Circle -> spocita obsah kruhu *)
(* circle_area bude po provedeni mit hodnotu 314 *)
circle_area := shape.Area();

END_PROGRAM

Přístup k vlastním položkám a položkám předků

Občas je potřeba, aby potomek přistoupil na položku předka nebo naopak vynutil přístup ke své položce. K tomu slouží klíčová slova SUPER (přístup k předkovi) a THIS (přístup k vlastní položce).

V následujícím příkladu existuje abstraktní předek Car s potomkem StreetCar, který má potomka Bmw. V metodě Description lze zjistit popis předka a spojit ho s vlastním popisem.

FUNCTION_BLOCK Car

METHOD VIRTUAL Description : STRING
END_METHOD

END_FUNCTION_BLOCK


FUNCTION_BLOCK StreetCar EXTENDS Car

METHOD VIRTUAL Description : STRING
Description := "STREET CAR";
END_METHOD

END_FUNCTION_BLOCK


FUNCTION_BLOCK Bmw EXTENDS StreetCar

METHOD VIRTUAL Description : STRING
(* vrati text od predka a prida k nemu svuj *)
(* Vysledkem metody tedy bude "STREET CAR BMW" *)
Description := CONCAT(SUPER.Description(), " BMW");
END_METHOD

END_FUNCTION_BLOCK

Další příklad:

FUNCTION_BLOCK Base

METHOD VIRTUAL Description : STRING

Description := "Base";

END_METHOD

END_FUNCTION_BLOCK

FUNCTION_BLOCK Descendant EXTENDS Base

METHOD VIRTUAL Description : STRING

Description := "Descendant";

END_METHOD

METHOD SuperDescription : STRING

(* Přesně specifikujeme, že jde o konkrétní metodu na předkovi. *)
SuperDescription := SUPER.Description();

END_METHOD

METHOD ThisDescription : STRING

(* THIS se nemusí uvádět. Implicitně se předpokládá jako nejbližší scope. *)
ThisDescription := THIS.Description();

END_METHOD

END_FUNCTION_BLOCK

PROGRAM this_super_prg
VAR
fb : Descendant;

desc, this_desc, super_desc : STRING;
END_VAR

desc := fb.Description(); // returns "Descendant"
this_desc := fb.ThisDescription(); // returns "Descendant"
super_desc := fb.SuperDescription(); // returns "Base"

END_PROGRAM

Vlastní kód výpočtu funkčního bloku

Klasický výpočet (tj. bez objektových rozšíření) funkčního bloku si lze v rámci metod představit jakožto metodu "main". Nemá vstupní parametry ani výstupní parametry a pracuje nad daty dostupnými z kódu výpočtu.

Tento kód je také možné pojmout jako virtuální. A to označením celého funkčního bloku jakožto virtuálního.

Př.:

FUNCTION_BLOCK VIRTUAL ScheduleBase

Rozhraní - Interface

Koncept rozhraní umožňuje oddělit implementaci a specifikaci vlastností, které musí implementace splňovat. Interface obsahuje množinu prototypů metod a neobsahuje jakékoliv datové položky a proměnné. Definice rozhraní je ohraničena klíčovými slovy INTERFACE a END_INTERFACE.

Užití interface je možné v definici funkčního bloku, což pak znamená, že funkční blok musí všechny metody předepsané interfacem implementovat. Na toto slouží klíčové slovo IMPLEMENTS. Druhé možné využití je specifikace typu proměnné. Do proměnná typu interface pak mohou být přiřazeny funkční bloky, které samy nebo v rámci nějakého předka, implementují interface.

Každý funkční blok může implementovat libovolné množství interface.

V následujícím příkladu existuje interface Room, který definuje metody, které se mají volat běhen dne a během noci. Tento interface je implementován funkčním blokem LightRoom, který reprezentuje pokoj s žárovkou. Během dne ji vypíná, v noci zapíná.

INTERFACE Room
METHOD DayTime END_METHOD // Called in day-time
METHOD NightTime END_METHOD // in night-time
END_INTERFACE

FUNCTION_BLOCK LightRoom IMPLEMENTS Room
VAR
Light: BOOL;
END_VAR

METHOD DayTime
Light:= FALSE;
END_METHOD

METHOD NightTime
Light:= TRUE;
END_METHOD

END_FUNCTION_BLOCK

Využití v programu:

PROGRAM light_rooms
VAR
kitchen : LightRoom;

room_interf : REF_TO Room;
END_VAR; // class instantiation

room_interf := REF kitchen;

room_interf.DayTime();

END_PROGRAM

Dědění interface

Dědění interface je obdobné jako dědění funkčních bloků. Také využívá klíčového slova EXTENDS. Stejně tak interface nemůže dědit více interface.

Funkční blok, který implementuje děděný nebo děděné interface musí implementovat sjednocení metod ze všech interface.

Příklad:

INTERFACE BaseA

METHOD A END_METHOD

END_INTERFACE


INTERFACE BaseB

METHOD B END_METHOD

END_INTERFACE

INTERFACE BaseC EXTENDS BaseA

METHOD C END_METHOD

END_INTERFACE

INTERFACE BaseD

METHOD D END_METHOD

END_INTERFACE


FUNCTION_BLOCK C IMPLEMENTS BaseC, BaseD

METHOD A END_METHOD
METHOD B END_METHOD
METHOD C END_METHOD
METHOD D END_METHOD

END_FUNCTION_BLOCK

Polymorfismus

Již z předešlého textu a příkladů je vidět, že v různých situacích může vystupovat předem neznámý typ. Až v době běhu programu dochází k aplikaci konkrétní instance. Toho lze velmi výhodně využít v zabstraktňování problému. Obecný algoritmus může řešit vše nad abstraktními typy a konkrétní implementace pak mohou být poskytovány i zcela jiným subjektem, než je tvůrce knihovny.

Polymorfismus lze využít v následujících případech:

  • Interface - jelikož interface nijak nespecifikuje implementaci, ale pouze kontakt s okolím, je vhodný pro oddělení algoritmů a implementace. Dobrým příkladem z jsou třeba transformace IO. GUI a celý systém předpokládá, že existuje interface definující transformace. Uživatel si pak může udělat libovolnou implementaci pro svá zařízení (př. různé rozsahy teploměrů apod.)
  • Hierarchie funkčních bloků - velmi podobné využití interface. Předkové mohou sloužit v obecnějších voláních a knihovnách podobně jako interface.
  • Virtuální metody - v případě volání na THIS je i v případě, že vlastní instance je předkem, volána vždy až metoda na posledním potomkovi.
  • REF_TO - do proměnných je možné přiřazovat odvozený funkčního bloku nebo interface (viz příklady).