假设我正在对我的家庭存储系统进行建模。我有一堆不同类型的Container
,我发现其中很多都有装饰品,所以我为这种常见情况设置了一些辅助代码。
容器中有我的Mantlepiece
和Bookcase
。我只在前者上存放装饰品;而后者则拥有所有的装饰品,以及精装和软装书。
这是一个初步尝试:
module Properties
def has_ornament
include OrnamentThings
end
module OrnamentThings
module Things
class Ornament
end
end
end
end
class Container
extend Properties
end
class Mantlepiece < Container
has_ornament
end
class Bookcase < Container
has_ornament
module Things
class Hardback
end
class Paperback
end
end
end
[Mantlepiece, Bookcase].each do |place|
puts place.name
puts place.constants.inspect
puts place::Things.constants.inspect
end
# Output:
# Mantlepiece
# [:Things]
# [:Ornament]
# Bookcase
# [:Things]
# [:Hardback, :Paperback]
你可以看到Mantlepiece
正确地嵌套了Mantlepiece::Things::Ornament
;但是Bookcase
的Things
的类内声明意味着Bookcase::Things
只嵌套Hardback
和Paperback
。 Bookcase::Things::Ornament
不见了。
我可以写得整齐吗,以便Bookcase
可以调用has_ornament
,然后声明自己的Things
集,并将它们全部嵌套在同一个命名空间中?
即使你的地幔和书柜都有东西,这些东西是不同的(因为它们包含不同的类(。因此,它们不能只包含一些常见的Things
模块;相反,他们必须定义自己单独的Things
,就像你在Bookcase
中通过声明module Things
所做的那样。
def has_ornament
const_set(:Things, Module.new) unless const_defined? :Things, false
self::Things.include OrnamentThings
end
module OrnamentThings
class Ornament
end
end
这是有效的,因为 Ruby 允许您使用与声明模块相同的语法重新打开模块。 has_ornament
定义了一个全新的Things
模块,然后打开该模块以添加更多内容。如果您在自定义内容之后调用 has_ornament
,它会跳过创建并添加到您创建的模块中(false
确保我们仅在当前类中查找Things
(。