Pochodzę z Javy i teraz pracuję więcej z Ruby.
Jedną z nieznanych mi funkcji językowych jest module
. Zastanawiam się, co to dokładnie jest module
i kiedy używasz jednego z nich, a po co używać go module
powyżej class
?
Pochodzę z Javy i teraz pracuję więcej z Ruby.
Jedną z nieznanych mi funkcji językowych jest module
. Zastanawiam się, co to dokładnie jest module
i kiedy używasz jednego z nich, a po co używać go module
powyżej class
?
Odpowiedzi:
Pierwsza odpowiedź jest dobra i zawiera odpowiedzi strukturalne, ale innym podejściem jest zastanowienie się nad tym, co robisz. Moduły polegają na udostępnianiu metod, których można używać w wielu klasach - pomyśl o nich jak o „bibliotekach” (jak zobaczysz w aplikacji Rails). Klasy dotyczą przedmiotów; moduły dotyczą funkcji.
Na przykład systemy uwierzytelniania i autoryzacji są dobrymi przykładami modułów. Systemy uwierzytelniania działają w wielu klasach na poziomie aplikacji (użytkownicy są uwierzytelnieni, sesje zarządzają uwierzytelnianiem, wiele innych klas będzie działać inaczej w zależności od stanu uwierzytelnienia), więc systemy uwierzytelniania działają jako wspólne interfejsy API.
Możesz także użyć modułu, jeśli udostępniasz metody w wielu aplikacjach (znowu model biblioteki jest tutaj dobry).
╔═══════════════╦═══════════════════════════╦═════════════════════════════════╗
║ ║ class ║ module ║
╠═══════════════╬═══════════════════════════╬═════════════════════════════════╣
║ instantiation ║ can be instantiated ║ can *not* be instantiated ║
╟───────────────╫───────────────────────────╫─────────────────────────────────╢
║ usage ║ object creation ║ mixin facility. provide ║
║ ║ ║ a namespace. ║
╟───────────────╫───────────────────────────╫─────────────────────────────────╢
║ superclass ║ module ║ object ║
╟───────────────╫───────────────────────────╫─────────────────────────────────╢
║ methods ║ class methods and ║ module methods and ║
║ ║ instance methods ║ instance methods ║
╟───────────────╫───────────────────────────╫─────────────────────────────────╢
║ inheritance ║ inherits behaviour and can║ No inheritance ║
║ ║ be base for inheritance ║ ║
╟───────────────╫───────────────────────────╫─────────────────────────────────╢
║ inclusion ║ cannot be included ║ can be included in classes and ║
║ ║ ║ modules by using the include ║
║ ║ ║ command (includes all ║
║ ║ ║ instance methods as instance ║
║ ║ ║ methods in a class/module) ║
╟───────────────╫───────────────────────────╫─────────────────────────────────╢
║ extension ║ can not extend with ║ module can extend instance by ║
║ ║ extend command ║ using extend command (extends ║
║ ║ (only with inheritance) ║ given instance with singleton ║
║ ║ ║ methods from module) ║
╚═══════════════╩═══════════════════════════╩═════════════════════════════════╝
Dziwię się, że nikt jeszcze tego nie powiedział.
Ponieważ pytający pochodził z języka Java (podobnie jak ja), oto analogia, która pomaga.
Klasy są po prostu jak klasy Java.
Moduły są jak klasy statyczne Java. Pomyśl o Math
klasie w Javie. Nie tworzysz go i ponownie używasz metod w klasie statycznej (np. Math.random()
).
extend self
), udostępniając swoje metody self
metaklasie. Umożliwia to wysłanie metody takiej jak random()
w Math
module. Ale ze względu na swój charakter metody modułu nie mogą być wywoływane samodzielnie self
. Ma to związek z pojęciem Ruby self
, jej metaklasami i działaniem wyszukiwania metod. Sprawdź „Metaprogramowanie Ruby” - Paolo Perlotta, aby uzyskać szczegółowe informacje.
Zasadniczo nie można utworzyć instancji modułu. Gdy klasa zawiera moduł, generowana jest nadklasa proxy, która zapewnia dostęp do wszystkich metod modułowych, a także metod klasowych.
Moduł może być zawarty w wielu klasach. Moduły nie mogą być dziedziczone, ale ten model „mixin” zapewnia użyteczny typ „wielokrotnego dziedziczenia”. OO, puryści, nie zgodzą się z tym stwierdzeniem, ale nie pozwólcie, aby czystość przeszkodziła w wykonaniu zadania.
(Ta odpowiedź była pierwotnie połączona z http://www.rubycentral.com/pickaxe/classes.html
tym linkiem, ale ten link i jego domena nie są już aktywne).
extend
wejście do klasy. Ruby tak naprawdę w ogóle nie rozróżnia metod „instancja” i „klasa / statyczny”, tylko ich odbiorniki.
Module
w Ruby, do pewnego stopnia, odpowiada klasie abstrakcyjnej Java - ma metody instancji, klasy mogą dziedziczyć po niej (przez include
, chłopaki Ruby nazywają to „mixinem”), ale nie ma instancji. Istnieją inne drobne różnice, ale tyle informacji wystarczy, aby zacząć.
przestrzeń nazw: moduły to przestrzenie nazw ... które nie istnieją w java;)
Zmieniłem też język Java i Python na Ruby, pamiętam, że miałem dokładnie to samo pytanie ...
Najprostszą odpowiedzią jest to, że moduł jest przestrzenią nazw, która nie istnieje w Javie. W Javie najbardziej zbliżonym do przestrzeni nazw jest pakiet .
Tak więc moduł w Rubim jest podobny do java:
class? Brak
interfejsu? Brak
klasy abstrakcyjnej? Brak
paczki? Tak, może)
metody statyczne wewnątrz klas w Javie: takie same jak metody wewnątrz modułów w Rubim
W Javie minimalną jednostką jest klasa, nie można mieć funkcji poza klasą. Jednak w Rubim jest to możliwe (jak Python).
Co wchodzi w moduł?
klasy, metody, stałe. Moduł chroni je pod tą przestrzenią nazw.
Brak instancji: modułów nie można używać do tworzenia instancji
Mieszane elementy: czasami modele dziedziczenia nie są dobre dla klas, ale pod względem funkcjonalności chcą zgrupować zestaw klas / metod / stałych razem
Reguły dotyczące modułów w Rubim:
- Nazwy modułów to UpperCamelCase
- stałe w modułach to WSZYSTKIE KAPSYKI (ta reguła jest taka sama dla wszystkich stałych ruby, nie dotyczy modułów)
- metody dostępu: użyj. operator
- stałe dostępu: użyj :: symbol
prosty przykład modułu:
module MySampleModule
CONST1 = "some constant"
def self.method_one(arg1)
arg1 + 2
end
end
jak korzystać z metod wewnątrz modułu:
puts MySampleModule.method_one(1) # prints: 3
jak używać stałych modułu:
puts MySampleModule::CONST1 # prints: some constant
Inne konwencje dotyczące modułów:
Użyj jednego modułu w pliku (np. Klasy ruby, jedna klasa na plik ruby)
Konkluzja: Moduł jest skrzyżowaniem klasy statycznej / użytecznej z mixinem.
Mixiny to fragmenty „częściowej” implementacji wielokrotnego użytku, które można łączyć (lub komponować) w sposób mix & match, aby pomóc pisać nowe klasy. Klasy te mogą dodatkowo mieć swój własny stan i / lub kod.
Klasa
Podczas definiowania klasy definiuje się plan dla typu danych. klasy przechowują dane, mają metodę, która wchodzi w interakcję z tymi danymi i są używane do tworzenia instancji obiektów.
Moduł
Moduły to sposób grupowania metod, klas i stałych.
Moduły dają dwie główne korzyści:
=> Moduły zapewniają przestrzeń nazw i zapobiegają konfliktom nazw. Przestrzeń nazw pomaga uniknąć konfliktów z funkcjami i klasami o tej samej nazwie, które zostały napisane przez kogoś innego.
=> Moduły implementują funkcję mixin.
(w tym moduł w Klazz daje instancjom dostęp do metod modułu.)
(rozszerz Klazza o Mod, dając klasie Klazz dostęp do metod Modów.)
Po pierwsze, pewne podobieństwa, o których jeszcze nie wspomniano. Ruby obsługuje otwarte klasy, ale moduły również są otwarte. W końcu klasa dziedziczy po module w łańcuchu dziedziczenia klas, a zatem klasa i moduł mają podobne zachowanie.
Ale musisz zadać sobie pytanie, jaki jest cel posiadania zarówno klasy, jak i modułu w języku programowania? Klasa ma być planem tworzenia instancji, a każda instancja jest zrealizowaną odmianą projektu. Instancja jest tylko zrealizowaną odmianą planu (Klasa). Oczywiście wtedy Klasy działają jak tworzenie obiektów. Ponadto, ponieważ czasami chcemy, aby jeden plan wywodził się z innego, Klasy mają na celu wspieranie dziedziczenia.
Nie można tworzyć instancji modułów, nie tworzyć obiektów i nie obsługiwać dziedziczenia. Pamiętaj więc, że jeden moduł NIE dziedziczy po innym!
Jaki jest więc sens posiadania modułów w języku? Jednym z oczywistych zastosowań modułów jest utworzenie przestrzeni nazw, a zauważysz to również w innych językach. Znów fajne w Ruby jest to, że można ponownie otworzyć moduły (podobnie jak klasy). Jest to duże zastosowanie, gdy chcesz ponownie użyć przestrzeni nazw w różnych plikach Ruby:
module Apple
def a
puts 'a'
end
end
module Apple
def b
puts 'b'
end
end
class Fruit
include Apple
end
> f = Fruit.new
=> #<Fruit:0x007fe90c527c98>
> f.a
=> a
> f.b
=> b
Ale nie ma dziedziczenia między modułami:
module Apple
module Green
def green
puts 'green'
end
end
end
class Fruit
include Apple
end
> f = Fruit.new
=> #<Fruit:0x007fe90c462420>
> f.green
NoMethodError: undefined method `green' for #<Fruit:0x007fe90c462420>
Moduł Apple nie odziedziczył żadnych metod z modułu Green, a kiedy umieściliśmy Apple w klasie Fruit, metody modułu Apple są dodawane do łańcucha przodków instancji Apple, ale nie metody z modułu Green, nawet jeśli Green moduł został zdefiniowany w module Apple.
Jak więc uzyskać dostęp do zielonej metody? Musisz wyraźnie dołączyć to do swojej klasy:
class Fruit
include Apple::Green
end
=> Fruit
> f.green
=> green
Ale Ruby ma inne ważne zastosowanie dla modułów. To jest funkcja Mixin, którą opisuję w innej odpowiedzi na SO. Podsumowując, mixiny pozwalają definiować metody w łańcuchu dziedziczenia obiektów. Za pomocą mixin można dodawać metody do łańcucha dziedziczenia instancji obiektów (dołącz) lub singleton_class self (przedłużyć).