Vor kurzem haben wir gesagt, dass Ruby keine Funktionen hat, sondern nur Methoden. Es gibt jedoch mehr als eine Methode. In diesem Kapitel werfen wir einen Blick auf die Zugangskontrolle.
Überlegen Sie, was passiert, wenn wir eine Methode auf der obersten Ebene definieren, nicht innerhalb einer Klassendefinition. Wir könnten denken, dass diese Methode einer Funktion in einer traditionelleren Sprache wie C ähnelt.
ruby> def square(n) | n * n | end nil ruby> square(5) 25
Unsere neue Methode scheint zu keiner Klasse zu gehören, aber Ruby gibt ihr die Klasse * Object *, die die Oberklasse jeder anderen Klasse ist. Daher kann jedes Objekt diese Methode verwenden. Das stimmt, aber es gibt einen kleinen Haken: Es ist eine private Methode für jede Klasse. Wir werden weiter unten besprechen, was dies bedeutet, aber eine der Auswirkungen davon ist, dass es nur in einem Funktionsstil wie diesem aufgerufen werden kann:
ruby> class Foo | def fourth_power_of(x) | square(x) * square(x) | end | end nil ruby> Foo.new.fourth_power_of 10 10000
Wir dürfen diese Methode nicht als Methode eines Objekts ausführen:
ruby> "fish".square(5) ERR: (eval):1: private method `square' called for "fish":String
Dies hält die objektorientierte Natur von Ruby sauberer (Funktionen sind immer noch Methoden des Objekts, aber der Empfänger ist implizit * self *), während Funktionen in einer traditionellen Sprache geschrieben werden können.
Der traditionelle Ansatz in der objektorientierten Programmierung, auf den wir in den letzten Kapiteln hingewiesen haben, ist die Aufteilung in Spezifikation und Implementierung bzw. welche Aufgaben ein Objekt erfüllen soll und wie diese tatsächlich ausgeführt werden. Das Innenleben des Objekts sollte in der Regel vor Benutzern verborgen bleiben. Sie müssen sich nur darum kümmern, welche Daten aus- und in das Objekt eingehen, und darauf vertrauen, dass das Objekt weiß, was mit den Daten in sich selbst zu tun ist. Daher ist es für Klassen oft nützlich, Methoden zu haben, die für die Außenwelt nicht sichtbar sind, aber intern verwendet werden (und vom Programmierer jederzeit verbessert werden können, ohne die Sicht des Benutzers auf das Objekt von außen zu ändern das übliche Beispiel, das folgt, stellen Sie sich engine als unsichtbaren internen Arbeiter der Klasse vor.
ruby> class Test | def times_two(a) | print a," times two is ",engine(a),"\n" | end | def engine(b) | b*2 | end | private:engine # this hides engine from users | end Test ruby> test = Test.new #<Test:0x4017181c> ruby> test.engine(6) ERR: (eval):1: private method `engine' called for #<Test:0x4017181c> ruby> test.times_two(6) 6 times two is 12. nil
Wir könnten erwarten, dass * test.engine (6) * ausgeführt wird, um 12 zurückzugeben, aber stattdessen sehen wir, dass * engine * nicht verfügbar ist, wenn der Benutzer sie auf eine Instanz der Klasse * Test * anwendet. Nur andere Methoden der Klasse Test , wie times_two , dürfen engien verwenden. Wir müssen die öffentliche Schnittstelle verwenden, die in der Methode * times \ _two enthalten ist * Der für diese Klasse verantwortliche Programmierer kann * engine * ändern (hier ist es möglich, von * b * 2 * zu * b + b . zu wechseln * um die Leistung zu verbessern) ohne zu berühren, wie der Benutzer mit den * Testobjekten interagiert * Dieses Beispiel ist natürlich sehr einfach, um nützlich zu sein; Die Vorteile der Zugangskontrolle werden erst deutlicher, wenn wir beginnen, komplexere und interessantere Klassen zu erstellen.