Різниця між класом і модулем


438

Я приїхав з Java, і зараз більше працюю з Рубі.

Однією з мовних особливостей я не знайомий є module. Мені цікаво, що саме таке moduleі коли ви використовуєте його, і навіщо використовувати moduleнад class?


Відповіді:


398

Перша відповідь хороша і дає деякі структурні відповіді, але інший підхід - подумати над тим, що ти робиш. Модулі полягають у наданні методів, які можна використовувати в декількох класах - подумайте про них як про "бібліотеках" (як ви побачили в додатку Rails). Заняття - про предмети; модулі відносяться до функцій.

Наприклад, системи аутентифікації та авторизації - хороші приклади модулів. Системи аутентифікації працюють у кількох класах на рівні додатків (користувачі проходять автентифікацію, сеанси керують автентифікацією, багато інших класів будуть діяти по-різному залежно від стану авторизації), тому системи аутентифікації діють як спільні API.

Можливо, ви також можете використовувати модуль, коли ви маєте спільні методи для кількох додатків (знову ж, модель бібліотеки тут хороша).


7
Чи модуль такий, як інтерфейси в Java?
Саад Рехман Шах

14
@Caffeine насправді не тому, що модулі Ruby насправді включають реалізацію, тоді як інтерфейси на Java абстрактні
Jorge Israel Peña

8
Ні, Модулі та пакети Java / JAR - абсолютно різні звірі.
Каролі Хорват

9
Мені більше подобаються абстрактні класи з реалізацією методу.
Automatico

2
Насправді @Chole стосується однієї з приємних речей щодо модулів: Розміщення імен. Тому, хоча Модулі не є прямим еквівалентом пакетів на Java, її можна використовувати для досягнення чогось подібного: 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)          ║
╚═══════════════╩═══════════════════════════╩═════════════════════════════════╝

Що таке суперклас класу 'Class'?
Aashish P

10
Я отримав ієрархію, Class -> Module -> Object -> BasicObject. Класно !!
Aashish P

Чому "модуль складається з" опущення змінних, коли класи і модулі підтримують змінні класу? Див загальноприйнятий відповідь на stackoverflow.com/questions/5690458 / ...
kaleidic

Дуже багато діаграм у всіх цих відповідях. Невеликий приклад: rubyfiddle.com/riddles/06081
Донато

16
Як модуль може "не бути екземпляром" і при цьому мати методи екземпляра?
Девіус

91

Я здивований, що хтось ще цього не сказав.

Оскільки запитувач походив з Java-програми (і це я зробив), ось аналогія, яка допомагає.

Заняття просто схожі на класи Java.

Модулі схожі на статичні класи Java. Подумайте про Mathзаняття на Java. Ви не інстанціюєте це, і ви повторно використовуєте методи в статичному класі (наприклад, Math.random()).


11
Але модулі також можуть додавати методи екземпляра до класу включення, тоді як статичні класи на Java не можуть.
Відновіть Моніку - немайнард

4
Це твердження також вірно з важкого C # фону.
Деймон Дрейк

5
Це не зовсім вірно; модулі не мають статичних методів, вони просто мають методи. Модулі можуть "розширюватися" (синтаксис є насправді extend self), роблячи свої методи доступними для їх selfметакласу. Це дає можливість відправити такий метод, як random()на Mathмодуль. Але за своєю природою методи модуля не можна викликати самостійно self. Це пов'язане з поняттям Рубі self, його метакласами та способом роботи методу пошуку. Перегляньте "Метапрограмування Ruby" - Паоло Перлотта для подробиць.
scottburton11

Я б сказав, що модулі більше схожі на інтерфейси з методами в них (інтерфейси Java 8 із замовчуванням impl), але не можуть успадкувати один від іншого, на відміну від інтерфейсів Java
divideByZero

Як ця відповідь має стільки голосів? До речі , що було сказано в кращих словах 1MO перед: stackoverflow.com/a/17027346/986862
Андре Фігуейред

39

По суті, модуль неможливо створити. Коли клас включає модуль, формується надклас проксі, який забезпечує доступ до всіх методів модуля, а також до методів класу.

Модуль може бути включений декількома класами. Модулі не можуть бути успадковані, але ця модель "міксина" забезпечує корисний тип "багаторазового успадкування". Пуристи ОО не погоджуються з цим твердженням, але не дозволяйте чистоті заважати виконувати роботу.


(Ця відповідь спочатку посилалася http://www.rubycentral.com/pickaxe/classes.html, але це посилання та його домен більше не активні.)


Так, це працює. Таким чином, модулі не можна порівняти з "статичними" класами Java; суперклас проксі (деякі називають його "метакласом") стає приймачем методу модуля відправки повідомлень, що робить його більш порівнянним зі статичним класом на Java, а його методи працюють як статичні методи. Те ж саме стосується класів Рубі, які можуть використовувати "статичні" подібні методи за extendдопомогою класу. Рубі насправді не розрізняє методи "екземпляр" та "клас / статичний" взагалі, лише їх приймачі.
scottburton11

7

Moduleу Ruby, до певної міри, відповідає абстракційному класу Java - має методи екземпляра, класи можуть успадковувати його (через include, хлопці Ruby називають це "mixin"), але не має жодних примірників. Є й інші незначні відмінності, але цієї інформації достатньо для початку роботи.


6

простір імен: модулі є просторами імен ... яких у Java не існує;)

Я також перейшов з Java та python на Ruby, пам’ятаю, було саме це питання ...

Отже, найпростіша відповідь полягає в тому, що модуль - це область імен, якої в Java не існує. У Java найбільш близьким до простору імен є пакет .

Тож модуль у рубіні - це як у java:
class? Немає
інтерфейсу? Немає
абстрактного класу? Немає
пакета? Так, можливо)

статичні методи всередині класів в java: такі ж, як методи всередині модулів в рубіні

У Java мінімальна одиниця - це клас, ви не можете мати функції поза класом. Однак в рубіні це можливо (як пітон).

Отже, що переходить у модуль?
класи, методи, константи. Модуль захищає їх під цим простором імен.

Ні в якому разі не можна використовувати модулі для створення екземплярів

Змішані дані: іноді моделі успадкування не підходять для класів, але з точки зору функціональності хочуть групувати набір класів / методів / констант разом

Правила щодо модулів в рубіні:
- Назви модулів
- UpperCamelCase - константи в модулях - ВСІ КАПС (це правило однакове для всіх констант рубіну, не характерне для модулів)
- методи доступу: використання. оператор
- константи доступу: use :: символ

простий приклад модуля:

module MySampleModule
  CONST1 = "some constant"

  def self.method_one(arg1)
    arg1 + 2
  end
end

як використовувати методи всередині модуля:

puts MySampleModule.method_one(1) # prints: 3

як використовувати константи модуля:

puts MySampleModule::CONST1 # prints: some constant

Деякі інші умовності щодо модулів:
Використовуйте один модуль у файлі (наприклад, класи рубіну, один клас на файл рубіну)


"- методи доступу: використання. оператор - константи доступу: використовуйте: символ ", тільки ця відповідь згадувала це!
Qiulang

4

Підсумок: Модуль - це перехрес між статичним / корисним класом та міксином.

Mixins - це багаторазові твори "часткової" реалізації, які можна комбінувати (або складати) у поєднанні та поєднанні, щоб допомогти писати нові класи. Ці класи, крім того, можуть мати власний стан та / або код.


1

Клас

Коли ви визначаєте клас, ви визначаєте креслення для типу даних. дані зберігання класу, мають метод, який взаємодіє з цими даними та використовується для інстанції об'єктів.

Модуль

  • Модулі - це спосіб групування методів, класів та констант.

  • Модулі дають дві основні переваги:

    => Модулі забезпечують простір імен та запобігають зіткненням імен. Простір імен допомагає уникнути конфліктів з функціями та класами з тим самим іменем, які написав хтось інший.

    => Модулі реалізують об'єкт mixin.

(включаючи модуль у Klazz, дає випадки доступу Klazz до методів Module.)

(розширення Klazz на Mod, що дає класу Klazz доступ до методів Mods.)


0

По-перше, деякі подібності, про які ще не було сказано. Ruby підтримує відкриті класи, але і модулі як відкриті. Зрештою, клас успадковує від модуля в ланцюжку успадкування класів, і тому Class і Module мають схожу поведінку.

Але вам потрібно запитати себе, яка мета мати клас і модуль мовою програмування? Клас призначений бути кресленням для створення екземплярів, і кожен екземпляр є реалізованою варіантом креслення. Екземпляр - це лише реалізована версія креслення (клас). Природно, тоді Класи функціонують як створення об'єктів. Крім того, оскільки ми іноді хочемо, щоб один план був похідний від іншого, Класи створені для підтримки успадкування.

Модулі не можуть бути екземплярами, не створювати об'єкти та не підтримувати успадкування. Тому пам’ятайте, що один модуль НЕ успадковує від іншого!

Тож тоді який сенс мати модулі в мові? Одне очевидне використання модулів - це створення простору імен, і ви це помітите і на інших мовах. Знову ж таки, що про Ruby прохолодно - це те, що модулі можна відкрити (як і класи). І це велике використання, коли потрібно повторно використовувати простір імен у різних файлах 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

Але немає спадкування між модулями:

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>

Модуль Apple не успадкував жодних методів із модуля Green, і коли ми включили Apple до класу Fruit, методи модуля Apple додаються до ланцюга предків екземплярів Apple, але не методи зеленого модуля, навіть якщо зелений модуль був визначений в модулі Apple.

Тож як ми отримуємо доступ до зеленого методу? Ви повинні явно включити його у свій клас:

class Fruit
  include Apple::Green
end
 => Fruit 
 > f.green
=> green

Але у Ruby є ще одне важливе використання модулів. Це об'єкт Міксіна, який я описую в іншій відповіді на ТА. Але підсумовуючи, міксини дозволяють визначати методи в ланцюжку спадкування об'єктів. Через mixins ви можете додати методи до ланцюжка успадкування об'єктів (включити) або singleton_class самості (розширити).

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.