Inne języki OOP mają klasy wewnętrzne, których nie można utworzyć bez powiązania z klasą wyższego poziomu. Na przykład w Javie
class Car {
class Wheel { }
}
tylko metody w Car
klasie mogą tworzyć Wheel
s.
Ruby nie ma takiego zachowania.
W Rubim
class Car
class Wheel
end
end
różni się od
class Car
end
class Wheel
end
tylko w nazwie klasy Wheel
vs. Car::Wheel
. Ta różnica w nazwie może wyraźnie wskazywać programistom, że Car::Wheel
klasa może reprezentować tylko koło samochodowe, w przeciwieństwie do koła ogólnego. Zagnieżdżanie definicji klas w Rubim jest kwestią preferencji, ale służy celowi w tym sensie, że silniej wymusza kontrakt między dwiema klasami, a tym samym przekazuje więcej informacji o nich i ich zastosowaniach.
Ale dla interpretera Rubiego to tylko różnica w nazwie.
Jeśli chodzi o drugą obserwację, klasy zagnieżdżone w modułach są zwykle używane do określania przestrzeni nazw klas. Na przykład:
module ActiveRecord
class Base
end
end
różni się od
module ActionMailer
class Base
end
end
Chociaż nie jest to jedyne użycie klas zagnieżdżonych w modułach, jest na ogół najpowszechniejsze.
Car.new
iCar::Wheel.new
. Zdecydowanie nie musisz inicjowaćCar
obiektu, aby zainicjowaćCar::Wheel
obiekt w Rubim, aleCar
klasa musi zostać załadowana i wykonana,Car::Wheel
aby była użyteczna.Car
aCar::Wheel
. Moduły (a tym samym klasy) to po prostu przestrzenie nazw dla stałych, w Rubim nie ma czegoś takiego jak klasa zagnieżdżona lub moduł zagnieżdżony.Car::Wheel.new
. Bum. Właśnie skonstruowałemWheel
obiekt, który nie jest zagnieżdżony wCar
obiekcie.W Rubim definiowanie klasy zagnieżdżonej jest podobne do definiowania klasy w module. W rzeczywistości nie wymusza asocjacji między klasami, po prostu tworzy przestrzeń nazw dla stałych. (Nazwy klas i modułów są stałymi).
Przyjęta odpowiedź nie była w niczym poprawna. 1 W poniższym przykładzie tworzę instancję klasy zamkniętej leksykalnie bez instancji tej klasy kiedykolwiek istniejącej.
Korzyści są takie same jak w przypadku modułów: hermetyzacja, grupowanie kodu używanego tylko w jednym miejscu i umieszczanie kodu bliżej miejsca, w którym jest używany. Duży projekt może mieć jeden moduł zewnętrzny, który pojawia się wielokrotnie w każdym pliku źródłowym i zawiera wiele definicji klas. Kiedy różne frameworki i kody bibliotek robią to wszystko, wtedy dodają tylko jedną nazwę do najwyższego poziomu, zmniejszając ryzyko konfliktów. Z pewnością prozaiczne, ale dlatego są używane.
Używanie klasy zamiast modułu do definiowania zewnętrznej przestrzeni nazw może mieć sens w jednoplikowym programie lub skrypcie, lub jeśli używasz już do czegoś klasy najwyższego poziomu lub jeśli faktycznie zamierzasz dodać kod łączący klasy ze sobą w prawdziwie klasycznym stylu. Ruby nie ma klas wewnętrznych, ale nic nie stoi na przeszkodzie, abyś tworzył w kodzie takie samo zachowanie. Odwoływanie się do obiektów zewnętrznych do obiektów wewnętrznych nadal będzie wymagało dotarcia z wystąpienia obiektu zewnętrznego, ale zagnieżdżenie klas będzie sugerować, że właśnie to możesz robić. Starannie zmodularyzowany program może zawsze najpierw utworzyć otaczające klasy i rozsądnie można je rozłożyć na klasy zagnieżdżone lub wewnętrzne. Nie możesz wywołać
new
modułu.Możesz użyć ogólnego wzorca nawet dla skryptów, w których przestrzeń nazw nie jest strasznie potrzebna, tylko dla zabawy i ćwiczeń ...
źródło
B
jest wewnątrz klasy . Stała się wewnątrz przestrzeni nazw klasy , ale nie ma absolutnie żadnego związku między obiektem wskazywanym przez (który w tym przypadku okazuje się być klasą) i klasy odwołuje .A
B
A
B
A
You can't call new on a module.
- więc w podstawowych kategoriach, jeśli chcę tylko nazwać niektóre klasy i nigdy nie muszę tworzyć instancji zewnętrznej „klasy”, to Użyłbym modułu zewnętrznego. Ale jeśli chcę utworzyć wystąpienie „klasy” opakowującej / zewnętrznej, uczyniłbym ją klasą zamiast modułem. Przynajmniej ma to dla mnie sens.Prawdopodobnie chcesz użyć tego do zgrupowania swoich klas w moduł. Coś w rodzaju przestrzeni nazw.
na przykład klejnot na Twitterze wykorzystuje przestrzenie nazw, aby to osiągnąć:
Tak więc obie
Client
iSearch
klasy mieszkają podTwitter
modułem.Jeśli chcesz sprawdzić źródła, kod obu klas można znaleźć tutaj i tutaj .
Mam nadzieję że to pomoże!
źródło
Istnieje jeszcze inna różnica między klasami zagnieżdżonymi a modułami zagnieżdżonymi w Rubim przed wersją 2.5, której inne odpowiedzi nie uwzględniły, o czym moim zdaniem należy tutaj wspomnieć. To jest proces wyszukiwania.
W skrócie: z powodu wyszukiwania stałych najwyższego poziomu w Rubim przed 2.5, Ruby może skończyć szukać twojej zagnieżdżonej klasy w złym miejscu (
Object
w szczególności), jeśli używasz zagnieżdżonych klas.W Rubim wcześniejszych niż 2.5:
Zagnieżdżona struktura klas: Załóżmy, że masz klasę
X
z zagnieżdżoną klasąY
lubX::Y
. A potem masz również klasę najwyższego poziomuY
. JeśliX::Y
nie jest załadowany, po wywołaniu dzieje się następującoX::Y
:Nie znaleziony
Y
wX
, Ruby spróbuje wyszukać go u przodkówX
. OdX
jest klasą, a nie modułem, ma przodków, wśród których są[Object, Kernel, BasicObject]
. Tak, stara się szukaćY
INObject
, jeżeli uzna go pomyślnie.Ale to najwyższy poziom
Y
i nieX::Y
. Otrzymasz to ostrzeżenie:Struktura modułu zagnieżdżonego: załóżmy, że w poprzednim przykładzie
X
jest to moduł, a nie klasa.Moduł ma tylko siebie jako przodka:
X.ancestors
będzie produkować[X]
.W takim przypadku Ruby nie będzie w stanie szukać
Y
u jednego z przodkówX
i wyrzuci plikNameError
. Railsy (lub jakikolwiek inny framework z automatycznym ładowaniem) spróbują załadować sięX::Y
później.Zobacz ten artykuł, aby uzyskać więcej informacji: https://blog.jetbrains.com/ruby/2017/03/why-you-should-not-use-a-class-as-a-namespace-in-rails-applications/
In Ruby 2.5:
Usunięto stałe wyszukiwanie najwyższego poziomu.
Możesz używać zagnieżdżonych klas bez obawy napotkania tego błędu.
źródło
Oprócz poprzednich odpowiedzi: Moduł w Rubim to klasa
źródło
new
. Więc chociaż można powiedzieć Moduły są klasą (małe litery), nie są one tak samo jak klasa (wielkimi literami) :)