Różnica między klasą a modułem

438

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 modulei kiedy używasz jednego z nich, a po co używać go modulepowyżej class?

Josh Moore
źródło

Odpowiedzi:

398

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).

scottru
źródło
7
Czy moduł jest taki sam jak interfejsy w java?
Saad Rehman Shah
14
@Caffeine nie do końca, ponieważ moduły Ruby zawierają implementacje, podczas gdy interfejsy w Javie są abstrakcyjne
Jorge Israel Peña
8
Nie, moduły i pakiety Java / JAR to zupełnie inne bestie.
Karoly Horvath,
9
Bardziej przypominam klasy abstrakcyjne z implementacją metod.
Automatico
2
W rzeczywistości @Chole natrafia na jedną z miłych rzeczy na temat modułów: Przestrzeń nazw. Więc chociaż moduły nie są bezpośrednim odpowiednikiem pakietów w Javie, można je wykorzystać do osiągnięcia czegoś podobnego: blog.rubybestpractices.com/posts/gregory/…
michaelok
513
╔═══════════════╦═══════════════════════════╦═════════════════════════════════╗
║               ║ 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)          ║
╚═══════════════╩═══════════════════════════╩═════════════════════════════════╝
Sergii Szewczyk
źródło
Jaka jest nadklasa klasy „Class”?
Aashish P
10
Mam hierarchię, Klasa -> Moduł -> Obiekt -> BasicObject. Fajne!!
Aashish P
Dlaczego „moduł składa się z” zmiennych pomijanych, gdy klasy i moduły obsługują zmienne klas? Zobacz zaakceptowaną odpowiedź na stackoverflow.com/questions/5690458/…
kaleidic
Wiele diagramów we wszystkich tych odpowiedziach. Mały przykładowy bieg: rubyfiddle.com/riddles/06081
Donato
16
W jaki sposób moduł „nie może być tworzony”, a mimo to ma metody instancji?
devius
91

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 Mathklasie w Javie. Nie tworzysz go i ponownie używasz metod w klasie statycznej (np. Math.random()).

Linan
źródło
11
Ale moduły mogą również dodawać metody instancji do klasy włącznie, podczas gdy klasy statyczne w Javie nie.
Przywróć Monikę - notmaynard
4
To stwierdzenie jest również prawdziwe, pochodzące z dużego tła w języku C #.
Damon Drake,
5
To nie do końca prawda; moduły nie mają metod statycznych, po prostu mają metody. Moduły mogą „rozszerzać się” (tak naprawdę jest składnia extend self), udostępniając swoje metody selfmetaklasie. Umożliwia to wysłanie metody takiej jak random()w Mathmodule. 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.
scottburton11
Powiedziałbym, że moduły są bardziej podobne do interfejsów z zawartymi w nich metodami (interfejsy Java 8 z domyślnym implem), ale nie mogą dziedziczyć się po sobie w przeciwieństwie do interfejsów Java
divideByZero
Jak ta odpowiedź ma tyle głosów? btw, co zostało powiedziane lepszymi słowami 1mo przed: stackoverflow.com/a/17027346/986862
Andre Figueiredo
39

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.htmltym linkiem, ale ten link i jego domena nie są już aktywne).

huragan
źródło
Tak, tak to działa. W związku z tym moduły nie są porównywalne z „statycznymi” klasami Javy; nadklasa proxy (niektórzy nazywają ją „metaklasą”) staje się odbiorcą komunikatów wysyłanych przez metodę modułu, co czyni bardziej porównywalną do klasy statycznej w Javie, a jej metody działają jak metody statyczne. To samo dotyczy klas Ruby, które mogą przyjmować metody „statyczne” poprzez extendwejście do klasy. Ruby tak naprawdę w ogóle nie rozróżnia metod „instancja” i „klasa / statyczny”, tylko ich odbiorniki.
scottburton11
7

Modulew 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ąć.

Boris Stitnicky
źródło
6

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)

apadana
źródło
„- metody dostępu: użyj. operator - stałe dostępu: use :: symbol ”tylko ta odpowiedź wspomniała o tym!
Qiulang,
4

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.

IQ Sayed
źródło
1

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.)

prasanthrubyist
źródło
0

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ć).

Donato
źródło