我对使用“include”vs“extend”感到困惑,在搜索了几个小时后,我得到的是模块方法与类的实例一起使用,包括模块,以及类扩展时类本身使用的模块方法这些方法的模块。
但这并没有帮助我弄清楚,为什么这段代码在“#extend Inventoryable”中评论扩展模块行时会出错 取消注释时工作,这是代码
module Inventoryable
def create(attributes)
object = new(attributes)
instances.push(object)
return object
end
def instances
@instances ||= []
end
def stock_count
@stock_count ||= 0
end
def stock_count=(number)
@stock_count = number
end
def in_stock?
stock_count > 0
end
end
class Shirt
#extend Inventoryable
include Inventoryable
attr_accessor :attributes
def initialize(attributes)
@attributes = attributes
end
end
shirt1 = Shirt.create(name: "MTF", size: "L")
shirt2 = Shirt.create(name: "MTF", size: "M")
puts Shirt.instances.inspect
输出
store2.rb:52:in `<main>': undefined method `create' for Shirt:Class (NoMethodError)
当取消注释“extend Inventoryable”以使代码工作时:
module Inventoryable
def create(attributes)
object = new(attributes)
instances.push(object)
return object
end
def instances
@instances ||= []
end
def stock_count
@stock_count ||= 0
end
def stock_count=(number)
@stock_count = number
end
def in_stock?
stock_count > 0
end
end
class Shirt
extend Inventoryable
include Inventoryable
attr_accessor :attributes
def initialize(attributes)
@attributes = attributes
end
end
shirt1 = Shirt.create(name: "MTF", size: "L")
shirt2 = Shirt.create(name: "MTF", size: "M")
puts Shirt.instances.inspect
使代码工作并输出以下内容
[#<Shirt:0x0055792cb93890 @attributes={:name=>"MTF", :size=>"L"}>, #<Shirt:0x0055792cb937a0 @attributes={:name=>"MTF", :size=>"M"}>]
它有点令人困惑,但我需要知道的是,为什么我需要扩展模块以避免错误?以及如何编辑此代码以使其在没有extend方法的情况下工作? ,代码中还剩下哪些依赖于扩展?
答案 0 :(得分:4)
当你extend
一个模块时,该模块中的方法变为&#34;类方法&#34; **。因此,当您extend Inventoryable
时,create
可用作Shirt
类的方法。
当你include
一个模块时,该模块中的方法变为&#34;实例方法&#34; **。因此,当您include Inventoryable
时,create
类上没有Shirt
,但<{1}}的实例上 可用。)
要在使用Shirt
时在create
课程中提供Shirt
,您可以使用include
挂钩。这可能看起来像:
included
然后,如果你这样做:
module Inventoryable
module ClassMethods
def create
puts "create!"
end
end
module InstanceMethods
end
def self.included(receiver)
receiver.extend ClassMethods
receiver.include InstanceMethods
end
end
你可以这样做:
class Shirt
include Invetoryable
end
**人群中的红宝石纯粹主义者会正确地指出,在ruby中,一切都是实例方法,并且没有类方法。这正式100%正确,但我们在这里使用> Shirt.create
create!
=> nil
和class
方法的口语含义。
答案 1 :(得分:1)
当你在一个类中扩展一个模块时,你将模块的方法暴露为类方法,但如果你包含模块,那么你将模块的方法作为实例方法,在你的例子中,你可以调用{{1您需要使用create
类的实例调用Inventoryable
类的方法(如果包含模块)
Shirt
如果没有更多信息,我无法确定您要尝试做什么,但您需要重新设计shirt1 = Shirt.new(attributes).create(attributes)
和initialize
方法,以确定在这些方法中的位置或操作。
我将尝试使用一个简单的例子来解释它
create
希望它有所帮助。
答案 2 :(得分:1)
在一天结束时,它非常简单:
C.include(M)
使C
的超类M
和M
的超类成为C
的超类。换句话说,它会将M
插入C
的祖先链。obj.extend(M)
(大致)与obj.singleton_class.include(M)
相同。