Einleitung: Objektorientierte Programmierung in R
Die objektorientierte Programmierung (OOP) ist ein Konzept, bei dem
Daten und zugehörige Funktionen in sogenannten Objekten
zusammengefasst werden. Dies fördert die Strukturierung,
Wiederverwendbarkeit und Wartbarkeit von Code – besonders bei
komplexeren Programmen.
R bietet dafür mehrere Systeme: S3,
S4 und das modernere, klassenbasierte
R6-System. Anders als S3 und S4 orientiert sich R6
stärker an klassischen OOP-Sprachen wie Python oder Java. Es erlaubt die
Definition von Klassen mit Konstruktoren, Methoden, Vererbung und
Zugriffskontrolle.
Ziel dieses Beispiels
In diesem Notebook definieren wir eine einfache R6-Klasse namens
Zahl
, die grundlegende Rechenoperationen kapselt:
Addition, Subtraktion,
Multiplikation und Division.
Dabei werden zwei häufige Fehlerquellen berücksichtigt:
- Division durch null
- Ungültiger Operand (z. B. kein
Zahl
-Objekt)
Das Beispiel dient als verständlicher Einstieg in OOP mit R6. Es
zeigt, wie man Werte und zugehörige Operationen in einer klaren,
objektorientierten Struktur verpackt und gleichzeitig robuste
Fehlerbehandlung integriert.
Klassendefinition
library(R6)
# Definition der Klasse "Zahl"
Zahl <- R6Class("Zahl",
public = list(
wert = NULL, # Attribut zur Speicherung des Zahlenwerts
# Konstruktor
initialize = function(wert) {
self$wert <- wert
},
# Addition
addiere = function(anderer) {
private$check_typ(anderer)
return(Zahl$new(self$wert + anderer$wert))
},
# Subtraktion
subtrahiere = function(anderer) {
private$check_typ(anderer)
return(Zahl$new(self$wert - anderer$wert))
},
# Multiplikation
multipliziere = function(anderer) {
private$check_typ(anderer)
return(Zahl$new(self$wert * anderer$wert))
},
# Division (mit Fehlerprüfung)
dividiere = function(anderer) {
private$check_typ(anderer)
if (anderer$wert == 0) stop("Fehler: Division durch null ist nicht erlaubt.")
return(Zahl$new(self$wert / anderer$wert))
},
# Ausgabe
anzeigen = function() {
cat("Wert:", self$wert, "\n")
}
),
private = list(
# Interne Typprüfung
check_typ = function(obj) {
if (!inherits(obj, "Zahl")) {
stop("Fehler: Argument ist kein Objekt der Klasse 'Zahl'.")
}
}
)
)
# Beispielnutzung
a <- Zahl$new(12)
a
<Zahl>
Public:
addiere: function (anderer)
anzeigen: function ()
clone: function (deep = FALSE)
dividiere: function (anderer)
initialize: function (wert)
multipliziere: function (anderer)
subtrahiere: function (anderer)
wert: 12
Private:
check_typ: function (obj)
b <- Zahl$new(4)
b
<Zahl>
Public:
addiere: function (anderer)
anzeigen: function ()
clone: function (deep = FALSE)
dividiere: function (anderer)
initialize: function (wert)
multipliziere: function (anderer)
subtrahiere: function (anderer)
wert: 4
Private:
check_typ: function (obj)
a$addiere(b)$anzeigen() # 12 + 4 = 16
Wert: 16
a$subtrahiere(b)$anzeigen() # 12 - 4 = 8
Wert: 8
a$multipliziere(b)$anzeigen() # 12 * 4 = 48
Wert: 48
a$dividiere(b)$anzeigen() # 12 / 4 = 3
Wert: 3
# Fehlerbeispiele (auskommentiert, damit sie den Code nicht abbrechen)
# a$dividiere(Zahl$new(0)) # Division durch null
# a$addiere("nicht_zahl") # Typfehler
LS0tCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCgojIyBFaW5sZWl0dW5nOiBPYmpla3RvcmllbnRpZXJ0ZSBQcm9ncmFtbWllcnVuZyBpbiBSCgpEaWUgb2JqZWt0b3JpZW50aWVydGUgUHJvZ3JhbW1pZXJ1bmcgKE9PUCkgaXN0IGVpbiBLb256ZXB0LCBiZWkgZGVtIERhdGVuIHVuZCB6dWdlaMO2cmlnZSBGdW5rdGlvbmVuIGluIHNvZ2VuYW5udGVuICpPYmpla3RlbiogenVzYW1tZW5nZWZhc3N0IHdlcmRlbi4gRGllcyBmw7ZyZGVydCBkaWUgU3RydWt0dXJpZXJ1bmcsIFdpZWRlcnZlcndlbmRiYXJrZWl0IHVuZCBXYXJ0YmFya2VpdCB2b24gQ29kZSDigJMgYmVzb25kZXJzIGJlaSBrb21wbGV4ZXJlbiBQcm9ncmFtbWVuLgoKUiBiaWV0ZXQgZGFmw7xyIG1laHJlcmUgU3lzdGVtZTogKipTMyoqLCAqKlM0KiogdW5kIGRhcyBtb2Rlcm5lcmUsIGtsYXNzZW5iYXNpZXJ0ZSAqKlI2LVN5c3RlbSoqLiBBbmRlcnMgYWxzIFMzIHVuZCBTNCBvcmllbnRpZXJ0IHNpY2ggUjYgc3TDpHJrZXIgYW4ga2xhc3Npc2NoZW4gT09QLVNwcmFjaGVuIHdpZSBQeXRob24gb2RlciBKYXZhLiBFcyBlcmxhdWJ0IGRpZSBEZWZpbml0aW9uIHZvbiBLbGFzc2VuIG1pdCBLb25zdHJ1a3RvcmVuLCBNZXRob2RlbiwgVmVyZXJidW5nIHVuZCBadWdyaWZmc2tvbnRyb2xsZS4KCiMjIyBaaWVsIGRpZXNlcyBCZWlzcGllbHMKCkluIGRpZXNlbSBOb3RlYm9vayBkZWZpbmllcmVuIHdpciBlaW5lIGVpbmZhY2hlIFI2LUtsYXNzZSBuYW1lbnMgYFphaGxgLCBkaWUgZ3J1bmRsZWdlbmRlIFJlY2hlbm9wZXJhdGlvbmVuIGthcHNlbHQ6ICoqQWRkaXRpb24qKiwgKipTdWJ0cmFrdGlvbioqLCAqKk11bHRpcGxpa2F0aW9uKiogdW5kICoqRGl2aXNpb24qKi4gCgpEYWJlaSB3ZXJkZW4gendlaSBow6R1ZmlnZSBGZWhsZXJxdWVsbGVuIGJlcsO8Y2tzaWNodGlndDoKCi0gKipEaXZpc2lvbiBkdXJjaCBudWxsKioKLSAqKlVuZ8O8bHRpZ2VyIE9wZXJhbmQgKHou4oCvQi4ga2VpbiBgWmFobGAtT2JqZWt0KSoqCgpEYXMgQmVpc3BpZWwgZGllbnQgYWxzIHZlcnN0w6RuZGxpY2hlciBFaW5zdGllZyBpbiBPT1AgbWl0IFI2LiBFcyB6ZWlndCwgd2llIG1hbiBXZXJ0ZSB1bmQgenVnZWjDtnJpZ2UgT3BlcmF0aW9uZW4gaW4gZWluZXIga2xhcmVuLCBvYmpla3RvcmllbnRpZXJ0ZW4gU3RydWt0dXIgdmVycGFja3QgdW5kIGdsZWljaHplaXRpZyByb2J1c3RlIEZlaGxlcmJlaGFuZGx1bmcgaW50ZWdyaWVydC4KCgojIyBLbGFzc2VuZGVmaW5pdGlvbgoKYGBge3J9CmxpYnJhcnkoUjYpCgojIERlZmluaXRpb24gZGVyIEtsYXNzZSAiWmFobCIKWmFobCA8LSBSNkNsYXNzKCJaYWhsIiwKICBwdWJsaWMgPSBsaXN0KAogICAgd2VydCA9IE5VTEwsICAjIEF0dHJpYnV0IHp1ciBTcGVpY2hlcnVuZyBkZXMgWmFobGVud2VydHMKICAgIAogICAgIyBLb25zdHJ1a3RvcgogICAgaW5pdGlhbGl6ZSA9IGZ1bmN0aW9uKHdlcnQpIHsKICAgICAgc2VsZiR3ZXJ0IDwtIHdlcnQKICAgIH0sCiAgICAKICAgICMgQWRkaXRpb24KICAgIGFkZGllcmUgPSBmdW5jdGlvbihhbmRlcmVyKSB7CiAgICAgIHByaXZhdGUkY2hlY2tfdHlwKGFuZGVyZXIpCiAgICAgIHJldHVybihaYWhsJG5ldyhzZWxmJHdlcnQgKyBhbmRlcmVyJHdlcnQpKQogICAgfSwKICAgIAogICAgIyBTdWJ0cmFrdGlvbgogICAgc3VidHJhaGllcmUgPSBmdW5jdGlvbihhbmRlcmVyKSB7CiAgICAgIHByaXZhdGUkY2hlY2tfdHlwKGFuZGVyZXIpCiAgICAgIHJldHVybihaYWhsJG5ldyhzZWxmJHdlcnQgLSBhbmRlcmVyJHdlcnQpKQogICAgfSwKICAgIAogICAgIyBNdWx0aXBsaWthdGlvbgogICAgbXVsdGlwbGl6aWVyZSA9IGZ1bmN0aW9uKGFuZGVyZXIpIHsKICAgICAgcHJpdmF0ZSRjaGVja190eXAoYW5kZXJlcikKICAgICAgcmV0dXJuKFphaGwkbmV3KHNlbGYkd2VydCAqIGFuZGVyZXIkd2VydCkpCiAgICB9LAogICAgCiAgICAjIERpdmlzaW9uIChtaXQgRmVobGVycHLDvGZ1bmcpCiAgICBkaXZpZGllcmUgPSBmdW5jdGlvbihhbmRlcmVyKSB7CiAgICAgIHByaXZhdGUkY2hlY2tfdHlwKGFuZGVyZXIpCiAgICAgIGlmIChhbmRlcmVyJHdlcnQgPT0gMCkgc3RvcCgiRmVobGVyOiBEaXZpc2lvbiBkdXJjaCBudWxsIGlzdCBuaWNodCBlcmxhdWJ0LiIpCiAgICAgIHJldHVybihaYWhsJG5ldyhzZWxmJHdlcnQgLyBhbmRlcmVyJHdlcnQpKQogICAgfSwKICAgIAogICAgIyBBdXNnYWJlCiAgICBhbnplaWdlbiA9IGZ1bmN0aW9uKCkgewogICAgICBjYXQoIldlcnQ6Iiwgc2VsZiR3ZXJ0LCAiXG4iKQogICAgfQogICksCiAgCiAgcHJpdmF0ZSA9IGxpc3QoCiAgICAjIEludGVybmUgVHlwcHLDvGZ1bmcKICAgIGNoZWNrX3R5cCA9IGZ1bmN0aW9uKG9iaikgewogICAgICBpZiAoIWluaGVyaXRzKG9iaiwgIlphaGwiKSkgewogICAgICAgIHN0b3AoIkZlaGxlcjogQXJndW1lbnQgaXN0IGtlaW4gT2JqZWt0IGRlciBLbGFzc2UgJ1phaGwnLiIpCiAgICAgIH0KICAgIH0KICApIAopCmBgYAoKCmBgYHtyfQojIEJlaXNwaWVsbnV0enVuZwphIDwtIFphaGwkbmV3KDEyKQphCmIgPC0gWmFobCRuZXcoNCkKYgpgYGAKCmBgYHtyfQphJGFkZGllcmUoYikkYW56ZWlnZW4oKSAgICAgICAgIyAxMiArIDQgPSAxNgphJHN1YnRyYWhpZXJlKGIpJGFuemVpZ2VuKCkgICAgIyAxMiAtIDQgPSA4CmEkbXVsdGlwbGl6aWVyZShiKSRhbnplaWdlbigpICAjIDEyICogNCA9IDQ4CmEkZGl2aWRpZXJlKGIpJGFuemVpZ2VuKCkgICAgICAjIDEyIC8gNCA9IDMKCmBgYAoKYGBge3J9CiMgRmVobGVyYmVpc3BpZWxlIChhdXNrb21tZW50aWVydCwgZGFtaXQgc2llIGRlbiBDb2RlIG5pY2h0IGFiYnJlY2hlbikKIyBhJGRpdmlkaWVyZShaYWhsJG5ldygwKSkgICAgICMgRGl2aXNpb24gZHVyY2ggbnVsbAojIGEkYWRkaWVyZSgibmljaHRfemFobCIpICAgICAgIyBUeXBmZWhsZXIKCmBgYAoK