Ruby Private Klassenmethoden

24 Jan 2016

In der Programmiersprache Ruby gibt es definierte Methoden in zwei Varianten: Instanzmethoden und Klassenmethoden. Instanzmethoden sind verfügbar, nachdem ein Objekt initialisiert und eine Instanz erstellt wurde. Klassenmethoden hingegen sind verfügbar, ohne eine Instanz der Klasse zu erstellen, für die sie definiert sind.

Ruby-Methoden können in der Sichtbarkeit variieren. Öffentliche Methoden sind in jedem Kontext verfügbar, während die Verfügbarkeit privater Methoden innerhalb der Instanz einer Klasse und ihrer Nachkommen eingeschränkt ist. Ein dritter Sichtbarkeitsbereich, protected , verhält sich ähnlich wie private Methoden, aber geschützte Methoden können von anderen Instanzen derselben Klasse aufgerufen werden.

Für eine schnelle Auffrischung sehen öffentliche und private Instanzmethoden folgendermaßen aus:

class Dog def do_trick bark end private def bark puts 'woof woof' endend

Wenn die öffentliche Methode aufgerufen wird:

> dog = Dog.new> dog.do_trick# => woof woof

Und die private Methode:

> dog = Dog.new> dog.bark# => NoMethodError: private method `bark' called for <Dog>

Private Klassenmethoden sind möglicherweise nicht so häufig wie private Instanzmethoden, aber sie haben immer noch ihren Platz. Zum Beispiel kann eine Klassenmethode interne Hilfsmethoden erfordern, um ihre Funktion abzuschließen. Was auch immer der Grund sein mag, das Definieren privater Klassenmethoden hat einen Wert, ist aber nicht immer intuitiv.

Diese Beispielklasse Dog muss eine Liste von tricks , die in den anderen öffentlichen Klassenmethoden verwendet werden. Diese Liste sollte für Anrufer außerhalb der Dog -Klasse nicht zugänglich sein.

Der falsche Weg

Ein erster Durchgang beim Schreiben der privaten tricks -Methode könnte folgendermaßen aussehen:

class Dog private def self.tricks endend

Beim Testen der Sichtbarkeit der tricks -Methode:

> Dog.tricks# => 

Uh oh, es wurde kein Fehler ausgegeben, der darauf hinweist, dass eine private Methode aufgerufen wurde.

Warum?

Der Grund, warum der obige Code keine private Methode erzeugt hat, hat mit Rubys Objekthierarchie, Interaktionen zwischen internen Klassen, Instanzen dieser Klassen und Eigenklassen zu tun. Eine detaillierte Beschreibung, wie Rubys Objekte miteinander arbeiten, finden Sie in einem früheren Beitrag.

Beim Definieren von Methoden in einer Klasse unterscheiden sich der Standardkontext und der durch die self. -Methodendeklaration eingeführte Kontext.

Der private Methodenbereich kann nicht auf die obige Weise verwendet werden, da er den Kontextwechsel zwischen Methoden, die in der Klasse Dog definiert und im Kontext self definiert sind, nicht behandelt.

Also, was sind die Alternativen?

class << self

Eine alternative Möglichkeit, Klassenmethoden für ein Objekt zu definieren, ist die Verwendung der Syntax class << self. Diese Syntax öffnet eine Eigenklasse für das angegebene Argument. In diesem Beispiel öffnet self innerhalb der Dog -Klasse die Dog's -Eigenklasse.

class Dog class << self private def tricks end endend

Zu beachten ist, dass sich bei der Definition solcher Methoden die Deklaration von def self.tricks zu einfach def tricks geändert hat.

Jetzt wird der private Bereich beibehalten und das erwartete Verhalten erreicht:

> Dog.tricks# => NoMethodError: private method `tricks' called for Dog:Class

Module

Module in Ruby sind Sammlungen von Methoden und Konstanten. Diese Sammlungen können als Kapselungswerkzeuge oder in diesem Fall als Alternative zur Definition öffentlicher und privater Klassenmethoden verwendet werden.

Wenn eine Klasse extends ein Modul ist, werden alle Methoden innerhalb dieses Moduls zu Klassenmethoden für die Subjektklasse*. Dieses Muster kann verwendet werden, um die tricks -Methode auf Dog zu definieren.

*Hinweis: Dies gilt nur für Methoden, die im „typischen Sinne“ definiert sind. def self. oder def Dog. Methodendefinitionen in einem Modul werden nicht automatisch zu Klassenmethoden auf die gleiche Weise, wenn extended .

class Dog module ClassMethods private def tricks end end extend ClassMethodsend> Dog.tricks# => NoMethodError: private method `tricks' called for Dog:Class

Ein Vorteil dieses Ansatzes ist die Lesbarkeit. Das Modul mit dem Namen ClassMethods, das in der Klasse Dog enthalten und somit gekapselt ist, ist die klare Heimat für alle gewünschten Klassenmethoden.

Sichtbarkeitsmodifikatoren wie private verhalten sich entsprechend und ein einfaches extend am unteren Rand der Moduldefinition bringt alles zusammen.

private_class_method

Ein dritter Ansatz ist die Verwendung der integrierten Methode Module#private_class_method. Der Zweck dieser Methode besteht darin, die Sichtbarkeit vorhandener Klassenmethoden zu ändern.

Im Gegensatz zu den beiden anderen Lösungen erfordert diese Lösung keinen anderen Stil der Methodendefinition als die falsche Lösung:

class Dog def self.tricks end private_class_method :tricksend> Dog.tricks# => NoMethodError: private method `tricks' called for Dog:Class

Diese Methode kann auch während der Methodendefinition der Klasse verwendet werden:

class Dog private_class_method def self.tricks endend> Dog.tricks# => NoMethodError: private method `tricks' called for Dog:Class

Wenn eine einzelne Klassenmethode privat sein muss und das Speichern von Zeilen sehr wichtig ist, kann dieser Stil anwendbar sein; aber es opfert sicherlich ein Maß an Lesbarkeit.

Eine große Stärke von private_class_method ist seine Eindeutigkeit. Im Gegensatz zu den anderen Ansätzen erfordert dieser keine spezielle Moduldefinition oder Methodendefinitionskontextwechsel.

Weiterführende Literatur

Die oben genannten Lösungen erledigen die Arbeit, beantworten jedoch möglicherweise nicht die anhaltenden Fragen, warum die Dinge so funktionieren, wie sie es tun. Ein paar großartige Artikel über die Ruby-Eigenklasse und Matz ‚Gedanken zum Ruby-Methodendesign sollten dazu beitragen, ein prägnanteres Bild davon zu zeichnen, warum Rubys private Klassenmethodendefinition komplex ist.

You might also like

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.