Objektorientierung
Mit Hilfe von Klassen ist es möglich, eigene komplexe Datentypen zu definieren. Eine Klasse stellt das Modell bzw. den Bauplan für Objekte dar. Eine Klasse kann mehrere Variablen (die sogenannten globalen Variablen), Eigenschaften (dazu weiter unten mehr) und Funktionen enthalten.
Objekte werden zu Laufzeit mittels des new
-Schlüsselworts erzeugt. Dieser Vorgang wird als sogenannte Instanziierung
bezeichnet. Bei der Deklaration von Objekt-Variablen wird als Datentyp der Klassenname angegeben. Die instanziierte
Objekt-Variable wird als Instanz bezeichnet.
Klassen werden innerhalb des package
-Blocks angegeben. Jede Klasse muss sich dabei in einer eigenen Datei
befinden. Vor dem Klassenblock wird der Zugriffsmodifizierer (dazu gleich mehr), das Schlüsselwort class
und der
eindeutige Name der Klasse angegeben. Dabei wird zumeist ebenfalls die Camel-Case-Schreibweise verwendet, jedoch mit
einem großen Buchstaben am Anfang des Namens. Innerhalb der Klasse können nun Variablen und Funktionen deklariert werden.
Sowohl für Klassen als auch für deren globale Variablen und Funktionen benötigen wir sogenannte Zugriffsmodifizierer.
Hier stehen uns die Schlüsselwörter private
, protected
und public
zur Verfügung. Bei
der Deklaration von Klassen wird stets public
verwendet. Die Verwendung von „privaten Klassen“ ist nicht zu
empfehlen und wird von dem Flex Compiler nicht mehr unterstützt, weshalb wir darauf nicht genauer eingehen. Doch nun zurück
zu den Unterschieden zwischen den Zugriffsmodifizierern. Mittels public
ist ein Zugriff von der Klasse selbst sowie
von „außen“ möglich. private
erlaubt den Zugriff auf die Variable bzw. Funktion nur von innerhalb der Klasse.
Der Zugriffsmodifizierer protected
ist mit private
zu vergleichen, jedoch ist bei protected
ein Zugriff von der Kindklasse auf die Variable oder Funktion der Elternklasse (siehe Vererbung) möglich.
In AS3 und anderen Programmiersprachen hat es sich eingebürgert, bei privaten Variablen einen Unterstrich _
voranzustellen
(siehe Beispiel). Das folgende Beispiel zeigt die Klasse Computer
, welche eine Variable für das Betriebssystem
(betriebsSystem
) und zwei Funktionen zum Hoch- und Runterfahren des Computers hat. Über die private Variable
_gestartet
, kann innerhalb der Klasse festgestellt werden, ob der Computer bereits gestartet ist. Der erste Code
zeigt die Objektinstanziierung sowie einige Zugriffe auf das Objekt. Im zweiten Code ist der Inhalt der Datei für die
Computer
-Klasse zu sehen.
var meinComputer:Computer = new Computer(); meinComputer.betriebsSystem = "Windows 7"; meinComputer.starteComputer(); meinComputer.starteComputer(); // Computer läuft bereits meinComputer.stoppeComputer(); meinComputer.stoppeComputer(); // Computer ist bereits heruntergefahren meinComputer.starteComputer();
Computer.as
package de.hwh.bsp.obj { public class Computer { private var _gestartet:Boolean = false; public var betriebsSystem:String; public function starteComputer():void { if (!_gestartet) { trace(betriebsSystem + " wird gestartet ..."); _gestartet = true; } else trace("Computer bereits gestartet!"); } public function stoppeComputer():void { if (_gestartet) { trace(betriebsSystem + " wird heruntergefahren ..."); _gestartet = false; } else trace("Computer läuft nicht!"); } } }
Ausgabe:
Windows 7 wird gestartet ... Computer bereits gestartet! Windows 7 wird heruntergefahren ... Computer läuft nicht! Windows 7 wird gestartet ...
Wichtig: In der Praxis sollten Variablen niemals mittels des Zugriffsmodifizierers public
von „außen“
zugänglich gemacht werden. Zum Ändern eines Variablenwertes sollten stets Funktionen (z. B. getX()
und
setX()
) oder Eigenschaften (siehe weiter unten) verwendet werden.
Übrigens: Sollten Sie innerhalb einer Klasse einen globalen Variablennamen haben, welcher den gleichen Namen wie eine lokale
Variable oder ein Funktionsparameter hat, dann können wir mittels des this
-Schlüsselworts eine Unterscheidung
durchführen. Das this
-Schlüsselwort verweist immer auf das aktuelle Objekt. Eine Verwendung von this
können Sie in den zwei folgenden Beispielen unten sehen.
Konstruktor
Der sogenannte Konstruktor ist eine spezielle Funktion, welche bei der Instanziierung ausgeführt wird. Deklariert wird die Funktion, so wie jede andere auch, jedoch muss beachtet werden, dass der Name der Konstruktorfunktion immer dem Klassennamen entsprechen muss. Des Weiteren fallen bei der Deklaration der Rückgabetyp sowie der vorangestellte Doppelpunkt weg. Das Verwenden von Parametern (und ggf. optionalen Parametern) bei der Konstruktorfunktion ist ebenfalls möglich (siehe Beispiel). Übergeben werden die Werte für die Konstruktorfunktion direkt in dem runden Klammernpaar bei Objektinstanziierung.
var meinComputer:Computer = new Computer("Windows 7"); meinComputer.starteComputer(); meinComputer.stoppeComputer(); meinComputer.starteComputer();
Computer.as
package de.hwh.bsp.objkonstruktor { public class Computer { private var _gestartet:Boolean = false; public var betriebsSystem:String; public function Computer(betriebsSystem:String) { this.betriebsSystem = betriebsSystem; } public function starteComputer():void { if (!_gestartet) { trace(betriebsSystem + " wird gestartet ..."); _gestartet = true; } else trace("Computer bereits gestartet!"); } public function stoppeComputer():void { if (_gestartet) { trace(betriebsSystem + " wird heruntergefahren ..."); _gestartet = false; } else trace("Computer läuft nicht!"); } } }
Ausgabe:
Windows 7 wird gestartet ... Windows 7 wird heruntergefahren ... Windows 7 wird gestartet ...
Vererbung
Bei der Vererbung wird eine bestehende Klasse um weitere Variablen, Eigenschaften und Funktionen erweitert. Bei der Klasse,
die Bestandteile von einer anderen Klassen erben soll, wird bei der Deklaration am Ende das Schlüsselwort extends
und
der Name der sogenannten Elternklasse angegeben. Bei der Elternklasse handelt es sich um die Klasse, von welcher Variablen,
Eigenschaften und Funktionen geerbt werden sollen. Bei der Klasse, die von einer anderen erbt, spricht man von der Kindklasse.
Über das Schlüsselwort super
können wir von der Kindklasse auf die Elternklasse zugreifen (z. B. um den Konstruktor
der Elternklasse aufzurufen). Des Weiteren ist es möglich, Funktionen der Elternklasse zu überschreiben. Hierfür notieren
wir das Schlüsselwort override
vor dem Zugriffsmodifizierer. Auch hier ist weiterhin ein Aufrufen der überschriebenen
Funktion (die zur Elternklasse gehört) möglich (siehe Beispiel). Im folgenden Beispiel handelt es sich bei der Klasse
Computer
um die Elternklasse (auch als Basisklasse bezeichnet). Die Klasse Notebook
hingegen ist die
Kindklasse.
var meinNotebook:Notebook = new Notebook("Windows 7", 15.6); meinNotebook.starteComputer(); meinNotebook.stoppeComputer();
Computer.as
package de.hwh.bsp.objvererbung { public class Computer { private var _gestartet:Boolean = false; public var betriebsSystem:String; public function Computer(betriebsSystem:String) { this.betriebsSystem = betriebsSystem; } public function starteComputer():void { if (!_gestartet) { trace(betriebsSystem + " wird gestartet ..."); _gestartet = true; } else trace("Computer bereits gestartet!"); } public function stoppeComputer():void { if (_gestartet) { trace(betriebsSystem + " wird heruntergefahren ..."); _gestartet = false; } else trace("Computer läuft nicht!"); } } }
Notebook.as
package de.hwh.bsp.objvererbung { public class Notebook extends Computer { public var displayGroesse:Number; public function Notebook(betriebsSystem:String, displayGroesse:Number) { super(betriebsSystem); this.displayGroesse = displayGroesse; } override public function starteComputer():void { super.starteComputer(); trace("Ihr Bildschirm mit " + displayGroesse.toFixed(1) + " Zoll wird initialisiert ..."); } } }
Ausgabe:
Windows 7 wird gestartet ... Ihr Bildschirm mit 15.6 Zoll wird initialisiert ... Windows 7 wird heruntergefahren ...
Eigenschaften
Eigenschaften sind die „besseren Variablen“. Wie bereits oben erwähnt, sollten Variablen nicht mittels public
von außen
zugänglich gemacht werden. Eigenschaften lösen dieses Problem, denn in Eigenschaften können wir einen Programmcode (z. B. zum Überprüfen
des zu setzenden Wertes) notieren, wie wenn es eine Funktion wäre. Vorteil gegenüber von Funktionen ist jedoch, dass sowohl zum Lesen
als auch zum Setzen der gleiche Name verwendet werden kann. Zudem ist die Zuweisung von außen mittels des Zuweisungsoperators einfacher
zu lesen als der Aufruf einer Funktion. Zur Speicherung des Wertes einer Eigenschaft wird eine (interne / private) Variable benötigt.
Eigenschaften sehen bei der Deklaration sehr ähnlich wie Funktionen aus. Zwischen dem Schlüsselwort function
und dem
Funktionsnamen bzw. Eigenschaftsnamen wird das Schlüsselwort get
oder set
notiert. Dadurch ist es möglich, nur
lesbare, nur änderbare und les- und änderbare Eigenschaften zu notieren. Die get
-Funktion der Eigenschaft hat immer einen
Rückgabewert, wohingegen die set
-Funktion immer einen Übergabeparameter hat.
var meinComputer:Computer = new Computer(); meinComputer.betriebsSystem = ""; meinComputer.starteComputer(); meinComputer.stoppeComputer(); meinComputer.betriebsSystem = "Windows 7"; meinComputer.starteComputer();
Computer.as
package de.hwh.bsp.objegst { public class Computer { private var _gestartet:Boolean = false; private var _betriebsSystem:String = "Windows 10"; public function get betriebsSystem():String { return _betriebsSystem; } public function set betriebsSystem(betriebsSystem:String):void { if (betriebsSystem != "") _betriebsSystem = betriebsSystem; } public function starteComputer():void { if (!_gestartet) { trace(betriebsSystem + " wird gestartet ..."); _gestartet = true; } else trace("Computer bereits gestartet!"); } public function stoppeComputer():void { if (_gestartet) { trace(betriebsSystem + " wird heruntergefahren ..."); _gestartet = false; } else trace("Computer läuft nicht!"); } } }
Ausgabe:
Windows 10 wird gestartet ... Windows 10 wird heruntergefahren ... Windows 7 wird gestartet ...
Packages
Mit Packages (oder auch als Paket bezeichnet) ist es möglich, Klassen zu gruppieren und zu bündeln. Ein Package ist immer der „oberste“ Block in einer Datei.
package de.hwh.bsp.oop { }
Die Namen von Packages bestehen zumeist aus mehreren Teilen und werden mittels des Punktoperators getrennt. So baut sich der Paketname
von links nach rechts zusammen. Alle unsere Beispiele befinden sich z. B. im Package de.hwh.bsp.*
. Dieser Name baut sich
aus den Teilnamen de
für Deutschland, hwh
für Homepage-WebHilfe und bsp
für Beispiel zusammen.
Die Gruppierung von Klassen in unterschiedliche Packages wird lediglich für größere Projekte verwendet.
Mittels des Schlüsselworts import
ist es möglich, Packages oder sogar einzelne Klassen einzubinden. Befindet sich z. B.
Klasse A
in einem anderen Package wie Klasse B
, so muss in der Datei von Klasse A
das Package
von Klasse B
importiert werden, sofern die Klasse B
innerhalb der Klasse A
verwendet wird. Die
import
-Anweisungen befinden sich direkt innerhalb des package
-Blocks oberhalb der Klassendefinition. Über das
Sternzeichen *
lassen sich alle Klassen eines Packages einbinden.
import de.hwh.bsp.oop.A; // Importiert die Klasse A des Packages de.hwh.bsp.oop
import de.hwh.bsp.oop.*; // Importiert alle Klassen des Packages de.hwh.bsp.oop
Übrigens: Der Zugriff auf Variablen und Funktionen einer Klasse sind nur möglich, wenn wir ein Objekt daraus instanziiert
haben. Um dies zu ändern, gibt es das Schlüsselwort static
. Dieses Schlüsselwort wird zwischen Zugriffsmodifizierer
und dem Schlüsselwort var
(bei Variablen), const
(bei Konstanten) oder function
(bei
Funktionen) angegeben. Geeignet sind statische Klassenbestandteile meistens nur für Konstanten (z. B. Math.PI
)
oder für Funktionen, die nicht direkt mit einem Objekt zusammenhängen bzw. Hilfsfunktionen sind (z. B. Math.ceil()
).