Ich bin ziemlich vertraut mit der Verwendung von Unterklassen und Modulen, aber in jüngerer Zeit habe ich verschachtelte Klassen wie diese gesehen:
class Foo
class Bar
# do some useful things
end
end
Sowie Klassen, die in Modulen wie diesen verschachtelt sind:
module Baz
class Quux
# more code
end
end
Entweder sind Dokumentation und Artikel spärlich oder ich bin nicht ausreichend über das Thema informiert, um nach den richtigen Suchbegriffen zu suchen, aber ich kann anscheinend nicht viele Informationen zu diesem Thema finden.
Könnte jemand Beispiele oder Links zu Beiträgen bereitstellen, warum / wann diese Techniken verwendet werden?
Car.new
und herzustellenCar::Wheel.new
. Sie müssen definitiv keinCar
Objekt initialisieren, um einCar::Wheel
Objekt in Ruby zu initialisieren , aber dieCar
Klasse muss geladen und ausgeführt werden, damitCar::Wheel
sie verwendet werden kann.Car
undCar::Wheel
. Module (und damit Klassen) sind einfach Namespaces für Konstanten. In Ruby gibt es keine verschachtelten Klassen oder verschachtelten Module.Car::Wheel.new
. Boom. Ich habe gerade einWheel
Objekt erstellt, das nicht in einemCar
Objekt verschachtelt ist .In Ruby ähnelt das Definieren einer verschachtelten Klasse dem Definieren einer Klasse in einem Modul. Es erzwingt keine Zuordnung zwischen den Klassen, sondern erstellt lediglich einen Namespace für die Konstanten. (Klassen- und Modulnamen sind Konstanten.)
Die akzeptierte Antwort war in nichts richtig. 1 Im folgenden Beispiel erstelle ich eine Instanz der lexikalisch eingeschlossenen Klasse, ohne dass jemals eine Instanz der einschließenden Klasse existiert.
Die Vorteile sind dieselben wie für Module: Kapselung, Gruppierung von Code, der nur an einer Stelle verwendet wird, und Platzierung des Codes näher an dem Ort, an dem er verwendet wird. Ein großes Projekt verfügt möglicherweise über ein äußeres Modul, das in jeder Quelldatei immer wieder vorkommt und viele Klassendefinitionen enthält. Wenn die verschiedenen Frameworks und Bibliothekscodes dies alle tun, tragen sie jeweils nur einen Namen zur obersten Ebene bei, wodurch die Wahrscheinlichkeit von Konflikten verringert wird. Natürlich prosaisch, aber deshalb werden sie verwendet.
Die Verwendung einer Klasse anstelle eines Moduls zum Definieren des äußeren Namespace kann in einem Programm oder Skript mit einer Datei sinnvoll sein, oder wenn Sie die Klasse der obersten Ebene bereits für etwas verwenden oder wenn Sie tatsächlich Code hinzufügen, um die Klassen miteinander zu verknüpfen im wahren Stil der inneren Klasse . Ruby hat keine inneren Klassen, aber nichts hindert Sie daran, ungefähr dasselbe Verhalten im Code zu erzeugen. Wenn Sie die äußeren Objekte von den inneren Objekten referenzieren, müssen Sie weiterhin von der Instanz des äußeren Objekts aus punktieren. Wenn Sie jedoch die Klassen verschachteln, wird dies möglicherweise der Fall sein. Ein sorgfältig modularisiertes Programm kann immer zuerst die einschließenden Klassen erstellen und sie können vernünftigerweise mit verschachtelten oder inneren Klassen zerlegt werden. Sie können kein
new
Modul aufrufen .Sie können das allgemeine Muster auch für Skripte verwenden, bei denen der Namespace nicht unbedingt benötigt wird, nur zum Spaß und zum Üben ...
quelle
B
ist nicht innerhalb der KlasseA
. Die KonstanteB
hat einen Namespace innerhalb der KlasseA
, aber es gibt absolut keine Beziehung zwischen dem Objekt, auf das verwiesen wirdB
(was in diesem Fall zufällig eine Klasse ist) und der Klasse, auf die verwiesen wirdA
.You can't call new on a module.
- Wenn ich also nur einige Klassen mit einem Namespace versehen möchte und dann nie eine Instanz der äußeren "Klasse" erstellen muss Ich würde ein äußeres Modul verwenden. Aber wenn ich eine Instanz der umhüllenden / äußeren "Klasse" instanziieren möchte, würde ich sie zu einer Klasse anstelle eines Moduls machen. Zumindest macht das für mich Sinn.Sie möchten dies wahrscheinlich verwenden, um Ihre Klassen in einem Modul zu gruppieren . Eine Art Namespace-Sache.
Das Twitter-Juwel verwendet beispielsweise Namespaces, um dies zu erreichen:
Also leben beide
Client
undSearch
Klassen unter demTwitter
Modul.Wenn Sie die Quellen überprüfen möchten, finden Sie den Code für beide Klassen hier und hier .
Hoffe das hilft!
quelle
Es gibt noch einen weiteren Unterschied zwischen verschachtelten Klassen und verschachtelten Modulen in Ruby vor 2.5, den andere Antworten nicht abdecken konnten, den ich hier erwähnen muss. Es ist der Suchprozess.
Kurz gesagt: Aufgrund der konstanten Suche auf oberster Ebene in Ruby vor 2.5 sucht Ruby möglicherweise (
Object
insbesondere) an der falschen Stelle nach Ihrer verschachtelten Klasse, wenn Sie verschachtelte Klassen verwenden.In Ruby vor 2.5:
Verschachtelte Klassenstruktur: Angenommen, Sie haben eine Klasse
X
mit verschachtelter KlasseY
oderX::Y
. Und dann haben Sie eine Top-Level-Klasse namensY
. WennX::Y
es nicht geladen ist, geschieht Folgendes, wenn Sie anrufenX::Y
:Wenn Ruby nicht gefunden
Y
wurdeX
, versucht es, es in Vorfahren von nachzuschlagenX
. Schon seitX
ist eine Klasse und kein Modul, es hat Vorfahren, darunter[Object, Kernel, BasicObject]
. So versucht sie zu suchen ,Y
inObject
, wo sie es erfolgreich findet.Dennoch ist es die oberste Ebene
Y
und nichtX::Y
. Sie erhalten diese Warnung:Verschachtelte Modulstruktur: Angenommen, im vorherigen Beispiel
X
handelt es sich um ein Modul und nicht um eine Klasse.Ein Modul hat nur sich selbst als Vorfahr:
X.ancestors
würde produzieren[X]
.In diesem Fall kann Ruby
Y
bei einem der Vorfahren von nicht suchenX
und wirft einenNameError
. Rails (oder ein anderes Framework mit automatischem Laden) versuchen danach zu ladenX::Y
.Weitere Informationen finden Sie in diesem Artikel: https://blog.jetbrains.com/ruby/2017/03/why-you-should-not-use-a-class-as-a-namespace-in-rails-applications/
In Ruby 2.5:
Konstante Suche auf oberster Ebene entfernt.
Sie können verschachtelte Klassen verwenden, ohne befürchten zu müssen, dass dieser Fehler auftritt.
quelle
Zusätzlich zu den vorherigen Antworten: Modul in Ruby ist eine Klasse
quelle
new
. Obwohl Sie sagen können, dass Module eine Klasse (Kleinbuchstaben) sind, sind sie nicht dasselbe wie eine Klasse (Großbuchstaben) :)