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