Answers:
第一个答案很好,并且给出了一些结构性答案,但是另一种方法是考虑您在做什么。模块是关于提供可在多个类中使用的方法的-将它们视为“库”(就像在Rails应用程序中看到的那样)。类是关于对象的。模块是关于功能的。
例如,身份验证和授权系统就是很好的模块示例。身份验证系统跨多个应用程序级别的类工作(用户已通过身份验证,会话管理身份验证,许多其他类将根据auth状态而有所不同),因此身份验证系统充当共享API。
当您在多个应用程序之间共享方法时,也可以使用模块(同样,库模型在这里很好)。
╔═══════════════╦═══════════════════════════╦═════════════════════════════════╗
║ ║ 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) ║
╚═══════════════╩═══════════════════════════╩═════════════════════════════════╝
我很惊讶没有人说这个。
由于问问者来自Java背景(我也是),因此有一个类比可以帮助您。
类就像Java类一样。
模块就像Java静态类。考虑一下Math
Java中的类。您没有实例化它,而是重用了静态类中的方法(例如Math.random()
)。
extend self
),使它们的方法可用于其self
元类。这样就可以random()
在Math
模块上分派类似的方法。但是,从本质上讲,不能独自调用模块的方法self
。这与Ruby的self
,其元类以及方法查找的工作方式有关。有关详细信息,请查看“元编程Ruby”-Paolo Perlotta。
基本上,该模块无法实例化。当类包含模块时,将生成代理超类,该代理超类提供对所有模块方法以及类方法的访问。
一个模块可以包含在多个类中。模块不能被继承,但是此“ mixin”模型提供了一种有用的“多重继承”类型。面向对象的纯粹主义者会不同意这种说法,但不要让纯洁妨碍完成工作。
(此答案最初链接到http://www.rubycentral.com/pickaxe/classes.html
,但是该链接及其域不再有效。)
extend
类来采用类似于“静态”的方法。Ruby实际上根本不区分“实例”和“类/静态”方法,仅区分它们的接收者。
名称空间:模块是名称空间 ...在Java中不存在;)
我也从Java和python切换到了Ruby,我记得有完全相同的问题...
因此,最简单的答案是模块是名称空间,Java中不存在该名称空间。在Java中,最接近命名空间的是软件包。
因此,ruby中的模块就像java:
class中的模块一样?没有
界面?没有
抽象类?没有
包吗?也许吧)
Java类内部的静态方法:与ruby模块内部的方法相同
在Java中,最小单位是一个类,您不能在一个类之外有一个函数。但是在ruby中这是可能的(例如python)。
那么模块中包含什么呢?
类,方法,常量。模块在该名称空间下保护它们。
没有实例:模块不能用于创建实例
混合输入法:有时继承模型不适用于类,但在功能方面希望将一组类/方法/常量组合在一起
关于ruby中模块的规则:
-模块名称是UpperCamelCase-
模块中的常量是ALL CAPS(此规则对于所有ruby常量都是相同的,不特定于模块)
-访问方法: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
关于模块的其他一些约定:
在文件中使用一个模块(例如ruby类,每个ruby文件一个类)
类
定义类时,将为数据类型定义一个蓝图。类保存数据,具有与该数据进行交互并用于实例化对象的方法。
模组
模块是将方法,类和常量分组在一起的一种方式。
模块为您带来两个主要好处:
=>模块提供名称空间并防止名称冲突。命名空间有助于避免与其他人编写的具有相同名称的函数和类发生冲突。
=>模块实现mixin工具。
(包括Klazz中的Module,使Klazz实例可以访问Module方法。)
(用Mod扩展Klazz,使Klazz类可以访问Mods方法。)
首先,一些相似之处尚未提及。Ruby支持开放类,但模块也开放。毕竟,Class继承自Class继承链中的Module,因此Class和Module确实具有某些相似的行为。
但是,您需要问自己:用编程语言同时拥有类和模块的目的是什么?一个类旨在作为创建实例的蓝图,每个实例都是该蓝图的一个实际变体。实例只是蓝图(类)的已实现变体。自然地,类充当对象创建。此外,由于有时我们希望一个蓝图可以从另一个蓝图派生,所以类被设计为支持继承。
模块不能实例化,不创建对象,也不支持继承。因此请记住,一个模块不会从另一个模块继承!
那么,使用某种语言的模块有什么意义呢?Modules的一种明显用法是创建一个名称空间,您还将在其他语言中注意到这一点。同样,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的另一个答案中对此进行了描述。但总而言之,mixin允许您将方法定义到对象的继承链中。通过mixin,可以将方法添加到对象实例的继承链(包括)或自身的singleton_class的继承链(扩展)。