Inhaltsverzeichnis
Klassen, Methoden und OOP
Hier geht es um Objekte, Klassen, Methoden und Eigenschaften. Kurz gesagt handelt es sich dabei um die OOP - Objekt-Orientierte-Programmierung.
Wenn Ihr bisher nur mit Programmiersprachen zu tun hattet, die nicht objektorientiert sind, hab Ihr am Anfang vielleicht etwas Schwierigkeiten, den Überblick zu behalten. Das liegt nicht zuletzt daran, das man bei OOP nicht mehr von Funktionen sondern von Methoden spricht und Variablen nennt man jetzt plötzlich Eigenschaften. Ich kann mich bis heute nicht mit diesen Begrifflichkeiten anfreunden.
Die Klasse
Unter einer Klasse kann man sich eine kleines Unterprogramm vorstellen. Diese Unterprogramm kann eigene Variablen (Eigenschaften) und Funktionen (Methoden) haben. Üblicherweise werden Klassen in eigenen Dateien ausgelagert, was die Übersicht erheblich verbessert. In unseren kleinen Beispielen steht die Klasse direkt im Hauptprogramm.
Das folgende kleine Script legt eine neue Klasse an.
# Definition einer Klasse mit dem Schlüsselwort 'class' # Der Klassenname muss mit einem Großbuchstaben beginnen class Kern # Funktionen innerhalb von Klassen nennt man Methoden def set_name(der_name : String) # Variablennamen die innerhalb der Klasse global gelten # werden mit @ geschrieben @name = der_name end # Diese Methode gibt den Inhalt der Variable @name zurück def get_name @name end end # Hauptprogramm # Eine neue Instanz von der Klasse Kern wird angelegt atom = Kern.new # die Variable '@name' in der Klasse belegen # dabei wird die Funktion 'set_name' aufgerufen und der Parameter 'Wasserstoff' übergeben atom.set_name "Wasserstoff" p! atom.get_name Ausgabe: atom.get_name # => "Wasserstoff"
Beim Instanziieren einer Klasse wird im Speicher eine Kopie der Klasse angelegt. Auf die Kopie kann man dann mit der zugewiessenen Variable 'atom' zugreifen. Der Methodenaufruf (Funktionsaufruf) einer Methode innerhalb einer Klasse wird mit dem '.' Operator veranlasst.
initialize oder der Konstruktor
Als Konstruktor versteht man eine spezielle Methode die direkt beim Anlegen einer Klasse aufgerufen wird. Guten Programmierstil verwendet diese Technik. Bei Crystal wird er Konstruktor als normale Methode mit dem Namen 'initialize' definiert.
class Kern # Konstruktor definieren def initialize(der_name : String) @name = der_name end def set_name(der_name : String) @name = der_name end def get_name @name end end # Eine neue Instanz von der Klasse Kern wird angelegt atom = Kern.new "Sauerstoff" p! atom.get_name # die Variable '@name' in der Klasse belegen atom.set_name "Wasserstoff" p! atom.get_name Ausgabe: atom.get_name # => "Sauerstoff" atom.get_name # => "Wasserstoff"
getters und setters
Im obigen Beispiel haben wird die Methoden 'set_name' und 'get_name' definiert. Solche Methoden nennt man Setter und Getter-Methoden.
Für diesen Zweck gibt es spezielle Makros.
class Kern # Setter Methode setter name # Getter Methode getter name # Konstruktor definieren def initialize(der_name : String) @name = der_name end end # Eine neue Instanz von der Klasse Kern wird angelegt atom = Kern.new "Sauerstoff" p! atom.name atom.name = "Wasserstoff" p! atom.name Ausgabe: atom.name # => "Sauerstoff" atom.name # => "Wasserstoff"
property
Anstelle von 'getter' _und_ 'setter' kann man auch einfach 'property' verwenden. Das Makro 'property' vereint die beiden anderen.
class Kern # property anstelle von getter und setter property name # Konstruktor definieren def initialize(der_name : String) @name = der_name end end # Eine neue Instanz von der Klasse Kern wird angelegt atom = Kern.new "Sauerstoff" p! atom.name atom.name = "Wasserstoff" p! atom.name Ausgabe: atom.name # => "Sauerstoff" atom.name # => "Wasserstoff"
Variablen Typen
In einer Klasse müssen die Typen von Variablen bestimmt werden. In den bisherigen Beispielen haben wir diese Bestimmung im Methodenaufruf vorgenommen (der_name : String).
Es gibt aber noch weitere Möglichkeiten:
Typbestimmung beim Makro
class Kern # Property Methode mit Typbestimmung property name : String # Konstruktor definieren def initialize(der_name) @name = der_name end end
Typbestimmung in der Klassenebene
class Kern # Typbestimmung in der Klassenebene @name : String property name # Konstruktor definieren def initialize(der_name) @name = der_name end end
Typbestimmung im Konstruktor durch Zuweisung eines Wertes
class Kern property name # Konstruktor definieren def initialize # Typ wird durch die Zuweisung bestimmt @name = "Silizium" end end
Typbestimmung in der Methodendefinition
class Kern property name # Variablen Typbestimmung mit "Default"-Wert def initialize(der_name = "Schwefel") @name = der_name end end
Klassenvariablen
Diese spezielle Art von Variablen gelten nicht wie üblich für jede einzelne Instanz einer Klasse, sonder über alle Instanzen hinweg.
class Kern # Klassenvariablen werden hier definiert # diese brauchen @@ vorangestellt @@id = 0_u32 # Geter und Setter auf id_instance property id_instance : UInt32 # Im Konstruktor könnte man einen Zähler laufen lassen def initialize @@id += 1 @id_instance = @@id end # das braucht man, um von aussen darauf zugreifen zu können def id @@id end end # Hauptprogramm wasserstoff = Kern.new sauerstoff = Kern.new # Die Klassenvariablen ist bei jeder Instanz gleich p! wasserstoff.id p! sauerstoff.id # Im Vergleich die Insantvariable p! wasserstoff.id_instance p! sauerstoff.id_instance Ausgabe: wasserstoff.id # => 2 sauerstoff.id # => 2 wasserstoff.id_instance # => 1 sauerstoff.id_instance # => 2