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


438

Я пришел с Java, и теперь я больше работаю с Ruby.

Одна из особенностей языка, с которой я не знаком, это module. Мне интересно, что именно moduleи когда вы используете один, и почему использовать более moduleчем class?


Ответы:


398

Первый ответ хорош и дает некоторые структурные ответы, но другой подход - подумать о том, что вы делаете. Модули предназначены для предоставления методов, которые вы можете использовать в нескольких классах - думайте о них как о «библиотеках» (как вы видели бы в приложении Rails). Классы об объектах; модули о функциях.

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

Вы также можете использовать модуль, когда у вас есть общие методы для нескольких приложений (опять же, модель библиотеки здесь хорошая).


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

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

8
Нет, Модули и Пакеты Java / JAR - совершенно разные звери.
Кароли Хорват

9
Я больше похож на абстрактные классы с реализацией метода.
Автомат

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)          ║
╚═══════════════╩═══════════════════════════╩═════════════════════════════════╝

Что такое суперкласс класса «Класс»?
Aashish P

10
Я получил иерархию, Класс -> Модуль -> Объект -> 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, его метаклассами и тем, как работает поиск методов. Проверьте "Метапрограммирование Руби" - Паоло Перлотта для деталей.
scottburton11

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

Откуда у этого ответа столько голосов? Кстати, это было сказано более хорошими словами за 1 месяц до этого: stackoverflow.com/a/17027346/986862
Андре Фигуейредо

39

По сути, модуль не может быть создан. Когда класс включает в себя модуль, создается прокси-суперкласс, который обеспечивает доступ ко всем методам модуля, а также к методам класса.

Модуль может быть включен несколькими классами. Модули не могут быть унаследованы, но эта модель "mixin" предоставляет полезный тип "множественного наследования". ОО-пуристы не согласятся с этим утверждением, но не позволяют чистоте мешать выполнению работы.


(Этот ответ изначально связан с http://www.rubycentral.com/pickaxe/classes.html, но эта ссылка и ее домен больше не активны.)


Да, вот как это работает. Таким образом, модули не сопоставимы с «статическими» классами Java; суперкласс прокси (некоторые называют его «метаклассом») становится получателем сообщений диспетчеризации метода модуля, что делает его более сопоставимым со статическим классом в Java, а его методы работают подобно статическим методам. Однако то же самое верно для классов Ruby, которые могут использовать «статические» методы, extendиспользуя класс. На самом деле Ruby вообще не различает методы «instance» и «class / static», только их получатели.
scottburton11

7

Moduleв Ruby, в некоторой степени, соответствует абстрактному классу Java - имеет методы экземпляра, классы могут наследовать от него (через include, ребята из Ruby называют его «mixin»), но не имеют экземпляров. Существуют и другие незначительные различия, но этого достаточно, чтобы начать работу.


6

namespace: модули - это пространства имен ... которые не существуют в java;)

Я также переключился с Java и Python на Ruby, я помню, был точно такой же вопрос ...

Таким образом, самый простой ответ заключается в том, что модуль является пространством имен, которого нет в Java. В Java самый близкий образ мышления к пространству имен - это пакет .

Таким образом, модуль в ruby ​​похож на то, что в java:
class? Нет
интерфейса? Нет
абстрактного класса? Нет
пакета? Да, может быть)

статические методы внутри классов в java: так же, как методы внутри модулей в ruby

В Java минимальной единицей является класс, у вас не может быть функции вне класса. Однако в ruby ​​это возможно (как в python).

Итак, что входит в модуль?
классы, методы, константы. Модуль защищает их в этом пространстве имен.

Нет экземпляра: модули не могут быть использованы для создания экземпляров

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

Правила для модулей в ruby:
- Имена модулей - UpperCamelCase
- константы внутри модулей - ВСЕ CAPS (это правило одинаково для всех констант ruby, не специфично для модулей)
- методы доступа: использовать. оператор
- константы доступа: используйте :: символ

Простой пример модуля:

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

Некоторые другие соглашения о модулях:
Используйте один модуль в файле (например, классы ruby, один класс на файл ruby)


«- методы доступа: использовать. оператор - константы доступа: используйте :: символ ”, только этот ответ упоминал об этом!
Qiulang

4

Итог: модуль представляет собой нечто среднее между статическим / служебным классом и миксином.

Миксины - это многократно используемые части «частичной» реализации, которые можно комбинировать (или составлять) в режиме «смешивать и сочетать», чтобы помочь в написании новых классов. Конечно, эти классы могут иметь собственное состояние и / или код.


1

Учебный класс

Когда вы определяете класс, вы определяете план для типа данных. класс содержит данные, имеет метод, который взаимодействует с этими данными и используется для создания экземпляров объектов.

модуль

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

  • Модули дают вам два основных преимущества:

    => Модули предоставляют пространство имен и предотвращают конфликты имен. Пространство имен помогает избежать конфликтов с функциями и классами с тем же именем, которые были написаны кем-то другим.

    => Модули реализуют смешанный механизм.

(Включение модуля в Klazz дает экземплярам доступа Klazz к методам модуля.)

(расширить Klazz с помощью Mod, предоставив классу Klazz доступ к методам Mods.)


0

Во-первых, некоторые сходства, которые еще не были упомянуты. Ruby поддерживает открытые классы, но модули также открыты. В конце концов, Class наследует от Module в цепочке наследования Class, и поэтому 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, но не в методы модуля Green, хотя Green модуль был определен в модуле Apple.

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

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

Но у Ruby есть еще одно важное применение для модулей. Это средство Mixin, которое я опишу в другом ответе на SO. Подводя итог, можно сказать, что миксины позволяют определять методы в цепочке наследования объектов. С помощью миксинов вы можете добавлять методы в цепочку наследования экземпляров объектов (include) или singleton_class класса self (extension).

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.