我正在阅读 Ruby,并了解了它的 mixins 模式,但想不出许多有用的 mixin 功能(因为我很可能不习惯以这种方式思考)。所以我想知道什么是有用的 Mixin 功能的好例子?
谢谢
编辑:一些背景知识。我来自 C++ 和其他对象语言,但我的疑问是 Ruby 说它不会继承 mixins,但我一直将 mixins 视为多重继承,所以我担心我太快地将它们分类到我的舒适区,并没有真正理解 mixin 是什么。
它们通常用于向类添加某种形式的标准功能,而无需全部重新定义。您可能会认为它们有点像 Java 中的接口,但不仅仅是定义需要实现的方法列表,其中许多实际上将通过包含模块来实现。 标准库中有一些示例:
Singleton - 可以混合到任何类中以使其成为单例的模块。初始化方法被设为私有,并添加了一个实例方法,这确保您的应用程序中只有该类的一个实例。
Comparable - 如果您将此模块包含在类中,则定义
方法(将当前实例与另一个对象进行比较并确定哪个更大)是否足以提供=、> 和 Between?方法。<=> <, <=, ==, >Enumerable - 通过混合此模块并定义
each方法,您可以获得对所有其他相关方法(例如收集、注入、选择和拒绝)的支持。如果它也有 方法,那么它也将支持排序、最小值和最大值。 <=>DataMapper 也是一个有趣的示例,展示了可以使用简单的 include 语句、采用标准类并添加将其持久保存到数据存储的功能来完成的操作。
module Persistence
def load sFileName
puts "load code to read #{sFileName} contents into my_data"
end
def save sFileName
puts "Uber code to persist #{@my_data} to #{sFileName}"
end
end
class BrandNewClass
include Persistence
attr :my_data
def data=(someData)
@my_data = someData
end
end
b = BrandNewClass.new
b.data = "My pwd"
b.save "MyFile.secret"
b.load "MyFile.secret"
想象该模块是由 Ruby ninja 编写的,它将类的状态保存到文件中。现在假设我编写一个全新的类,我可以通过说
include ModuleILike
混合它来重用持久性功能。您甚至可以在运行时包含模块。我只需将其混合即可免费获得加载和保存方法。这些方法就像您自己为班级编写的方法一样。代码/行为/功能-无需继承即可重用!
对您的类可用;如果你按照相反的顺序做,它就会。 这就像点一个蛋卷冰淇淋。如果你得到巧克力糖粉和太妃糖碎片作为你的混合物,然后带着你的甜筒走开,即使有人在冰淇淋店的巧克力糖粉箱中添加五彩糖粉,你所拥有的冰淇淋类型也不会改变。你的类(冰淇淋甜筒)没有被修改,而 mixin 模块(洒水箱)却被修改了。下一个使用该 mixin 模块的人将会看到这些变化。
当您在 ruby 中
include
某个模块时,它会在该模块上调用
Module#append_features
,这会将该模块的方法的副本一次添加到包含器中。多重继承,据我理解,更像是委托。如果你的班级不知道该怎么做,就会询问家长。在开放类环境中,类的父级可能在类创建后已被修改。
这就像RL亲子关系。你出生后,你的母亲可能已经学会了如何杂耍,但如果有人要求你杂耍,而你要求她要么:向你展示如何(当你需要时复制)或为你做(纯粹委托),那么她到那时就能够了,即使你是在她具备杂耍能力之前被创造出来的。
您可以通过修改
Module#append_features
来保留包含器列表,然后使用
method_added
回调更新它们,从而修改 ruby 模块“include”,使其更像多重继承,但这将是一个很大的转变来自标准 Ruby,并且在与其他代码一起使用时可能会导致重大问题。您可能最好创建一个调用 Module#inherit
并处理委托的 include
方法。对于现实世界的例子,
Enumerable
非常棒。如果您定义
#each
并在您的类中包含 Enumerable
,那么您就可以访问一整套迭代器,而无需对每个迭代器进行编码。