Difference between a class and a module
我来自Java,现在我正在使用Ruby。
我不熟悉的一个语言功能是
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | ╔═══════════════╦═══════════════════════════╦═════════════════════════════════╗ ║ ║ 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) ║ ╚═══════════════╩═══════════════════════════╩═════════════════════════════════╝ |
第一个答案是好的并给出了一些结构性答案,但另一种方法是考虑你正在做什么。模块是关于提供可以在多个类中使用的方法 - 将它们视为"库"(正如您在Rails应用程序中看到的那样)。类是关于对象的;模块是关于功能的。
例如,身份验证和授权系统是模块的好例子。身份验证系统跨多个应用程序级别的类(用户进行身份验证,会话管理身份验证,许多其他类将根据身份验证状态采取不同的行为),因此身份验证系统充当共享API。
当您在多个应用程序之间共享方法时,您也可以使用模块(同样,库模型在这里很好)。
我很惊讶有人还没说过这个。
由于提问者来自Java背景(我也是如此),这是一个有用的类比。
类就像Java类一样。
模块就像Java静态类。想想Java中的
基本上,模块无法实例化。当一个类包含一个模块时,会生成一个代理超类,它提供对所有模块方法以及类方法的访问。
多个类可以包含一个模块。模块不能被继承,但这种"mixin"模型提供了一种有用的"多重继承"类型。 OO纯粹主义者不同意这种说法,但不要让纯度妨碍完成工作。
(此答案最初链接到
Ruby中的
namespace:modules是命名空间...在java中不存在;)
我也从Java和python切换到Ruby,我记得有同样的问题......
所以最简单的答案是模块是一个名称空间,它在Java中不存在。在java中,最接近命名空间的思维方式是一个包。
所以ruby中的模块就像java中的模块一样:
类?没有
接口?没有
抽象类?没有
包?也许吧)
java中类的静态方法:与ruby中的模块内部的方法相同
在java中,最小单位是一个类,你不能在类之外有一个函数。但是在ruby中这是可能的(比如python)。
什么进入模块?
类,方法,常量。模块在该命名空间下保护它们。
没有实例:模块不能用于创建实例
混合ins:有时继承模型不适合类,但在功能方面希望将一组类/方法/常量组合在一起
关于ruby中模块的规则:
- 模块名称为UpperCamelCase
- 模块中的常量是ALL CAPS(对于所有ruby常量,此规则是相同的,不是特定于模块)
- 访问方法:使用。操作者
- 访问常量:use :: symbol
模块的简单示例:
1 2 3 4 5 6 7 | module MySampleModule CONST1 ="some constant" def self.method_one(arg1) arg1 + 2 end end |
如何在模块中使用方法:
1 | puts MySampleModule.method_one(1) # prints: 3 |
如何使用模块的常量:
1 | puts MySampleModule::CONST1 # prints: some constant |
关于模块的一些其他约定:
在文件中使用一个模块(如ruby类,每个ruby文件一个类)
底线:模块是静态/实用程序类和mixin之间的交叉。
Mixins是可重复使用的"部分"实现的部分,可以以混合和匹配的方式组合(或组合),以帮助编写新的类。当然,这些类还可以具有它们自己的状态和/或代码。
类
定义类时,可以为数据类型定义蓝图。
class hold data,具有与该数据交互的方法,用于实例化对象。
模
-
模块是一种将方法,类和常量分组在一起的方法。
-
模块为您带来两大好处:
=>模块提供命名空间并防止名称冲突。
命名空间有助于避免与其他人编写的具有相同名称的函数和类冲突。=>模块实现mixin工具。
(including Module in Klazz gives instances of Klazz access to Module
methods. )(extend Klazz with Mod giving the class Klazz access to Mods methods.)
首先,还有一些尚未提及的相似之处。 Ruby支持开放类,但模块也是开放的。毕竟,Class继承自Class继承链中的Module,因此Class和Module确实有类似的行为。
但是你需要问自己在编程语言中同时使用类和模块的目的是什么?一个类旨在成为创建实例的蓝图,每个实例都是蓝图的实现变体。实例只是蓝图(Class)的实现变体。当然,Classes用作对象创建。此外,由于我们有时希望从另一个蓝图派生出一个蓝图,因此Classes旨在支持继承。
模块无法实例化,不创建对象,也不支持继承。所以请记住,一个模块不会继承另一个模块!
那么在一种语言中使用模块有什么意义呢?模块的一个显而易见的用法是创建命名空间,您也会注意到其他语言。同样,Ruby的优点在于可以重新打开模块(就像类一样)。当您想在不同的Ruby文件中重用名称空间时,这是一个很重要的用法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | 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 |
但模块之间没有继承:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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模块在Apple模块中定义。
那么我们如何获得绿色方法的访问权限呢?您必须在您的班级中明确包含它:
1 2 3 4 5 6 | class Fruit include Apple::Green end => Fruit > f.green => green |
但是Ruby有另一个重要的用途。这是Mixin工具,我在SO的另一个答案中描述。但总而言之,mixins允许您将方法定义到对象的继承链中。通过mixins,您可以将方法添加到对象实例(包含)的继承链或self(extend)的singleton_class中。