包含模块时使用间接是否有优势(来自 7 周内的 7 种语言,Ruby 第 3 天)
Bruce 在“七周内的七种语言”,Ruby 第 3 天,第 38 页中给出了以下示例:
module ActsAsCsv
def self.included(base)
base.extend ClassMethods
end
module ClassMethods
def acts_as_csv
include InstanceMethods
end
end
module InstanceMethods
def read
#fill @csv_contents and @headers from file self.class.to_s.downcase + '.txt'
end
attr_accessor :headers, :csv_contents
def initialize
read
end
end
end
class RubyCsv
include ActsAsCsv
acts_as_csv
end
m = RubyCsv.new
puts m.headers.inspect
puts m.csv_contents.inspect
我看不出 def self.included(base)
和 使用间接寻址的任何原因类方法
。与简单地包含模块 InstanceMethods 相比,上述代码是否有优势?
详细来说:对于“简单地包含模块 InstanceMethods”,我指的是以下代码:
module InstanceMethods #defined as above
def read
#fill @csv_contents and @headers from file self.class.to_s.downcase + '.txt'
end
attr_accessor :headers, :csv_contents
def initialize
read
end
end
class RubyCsv
include InstanceMethods
end
m = RubyCsv.new
puts m.headers.inspect
puts m.csv_contents.inspect
由于鸭子类型,这不是和通过 base.extend ClassMethods
一样好吗?
Bruce gives the following example in "Seven languages in seven weeks", Ruby day 3, page 38:
module ActsAsCsv
def self.included(base)
base.extend ClassMethods
end
module ClassMethods
def acts_as_csv
include InstanceMethods
end
end
module InstanceMethods
def read
#fill @csv_contents and @headers from file self.class.to_s.downcase + '.txt'
end
attr_accessor :headers, :csv_contents
def initialize
read
end
end
end
class RubyCsv
include ActsAsCsv
acts_as_csv
end
m = RubyCsv.new
puts m.headers.inspect
puts m.csv_contents.inspect
I do not see any reason for the indirection used by def self.included(base)
and ClassMethods
. Is there an advantage of the above code over simply including the module InstanceMethods?
In detail: With "simply including the module InstanceMethods" I mean the following code:
module InstanceMethods #defined as above
def read
#fill @csv_contents and @headers from file self.class.to_s.downcase + '.txt'
end
attr_accessor :headers, :csv_contents
def initialize
read
end
end
class RubyCsv
include InstanceMethods
end
m = RubyCsv.new
puts m.headers.inspect
puts m.csv_contents.inspect
Because of duck typing, isn't this just as good as going via base.extend ClassMethods
?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
原始代码允许您执行此操作:
则会更干净
A
acts_as_csv 以外的更多方法, >ActsAsCsv
预计会被许多类继承的类包含(例如某种BaseModel
),时会产生进一步的优势
acts_as_csv
方法 > 比仅包含InstanceMethods
acts_as_csv
需要一个参数,例如acts_as_csv :separator =>; “”
The original code allows you to do this:
While using inheritance is more a matter of taste in this case it would be cleaner if
acts_as_csv
would be added similarly toA
ActsAsCsv
would be expected to be included by a class from which many classes inherit (like some kind ofBaseModel
)Further advantage arise when
acts_as_csv
is more elaborate than just includingInstanceMethods
acts_as_csv
takes an argument, for exampleacts_as_csv :separator => " "
优点之一是代码(和原始作者)与后来推理代码的人之间的目的沟通。 (以及允许参数的机制。)
acts_as_csv 说明了 RubyCsv 行为的一个方面。
include ActsAsCsv
的声明性较少。它是否提供了额外的方法,是否从根本上改变了底层类的功能,或者两者兼而有之,或者......?在阅读文档之前你不会知道。在阅读acts_as_csv
的文档之前,您可能也不知道,但它更具沟通性。这是“这就是我”和“这就是我可能做的”之间的区别。不要陷入具体的例子中——考虑正在做什么以及如何做的机制。
这种机制是 Ruby 代码看起来像它试图解决的问题而不仅仅是 Ruby 的原因之一。这是实现 micro-DSL 的一种方法,有助于使 Ruby 尽可能具有表现力。
One advantage is communication of purpose, between the code (and original writer) and those reasoning about the code later. (And the mechanics of allowing parameters.)
acts_as_csv
states an aspect ofRubyCsv
's behavior.include ActsAsCsv
is less declarative. Does it provide additional methods, does it fundamentally alter the functionality of the underlying class, or both, or...? You won't know until you read the docs. You might not know until you read the docs foracts_as_csv
, either, but it's more communicative.It's the difference between "this is what I am", and "this is what I may do". Don't get caught up in the specific example–consider the mechanics of what is being done, and how.
This mechanism is one reason Ruby code can look like the problem it's trying to solve instead of just Ruby. It's one way of implementing the micro-DSLs that help make Ruby as expressive as it is.