我目前正在以番石榴的Interner风格实现一个内部人员,其中:
当然,在Ruby中,您可以替换new和[]这样的方法,所以我的实现就是这样做的:
module Interner
def self.extended(obj)
intern_pool = Hash.new do |hash, key|
# Ideally, this should be a deep freeze, but it's not supported
# (see http://bugs.ruby-lang.org/issues/show/2509).
if key.respond_to?(:clone)
key = key.clone
key.freeze if key.respond_to?(:freeze)
end
hash[key] = key
end
[:new, :[]].each do |name|
if obj.respond_to?(name)
obj.singleton_class.module_exec(obj.method(name)) do |orig|
define_method name do |*args, &block|
intern_pool[orig[*args, &block]]
end
end
end
end
end
end示例用法:
Foo = Struct.new :foo, :bar do
extend Interner
end
a = Foo[1, 2]
b = Foo[3, 4]
c = Foo.new(1, 2)
d = Foo.new(3, 4)
a.equal?(c) # => true
b.equal?(d) # => true我意识到我的实现并不完美。你能推荐哪些改进措施?
发布于 2014-01-06 17:20:43
我看不出什么我会改变的。这是一个很好的概念,做得很好。我不会改变太多。首先是小事。
我会考虑将参数名从Interner.extended从obj更改为klass。
作为“很多小方法”粉丝俱乐部的一员,我认为:
def self.extended(klass)
intern_pool = make_intern_pool
...
end
def self.make_intern_pool
Hash.new do |hash, key|
key = freeze_key(key)
hash[key] = key
end
end
def self.freeze_key(key)
# Ideally, this should be a deep freeze, but it's not supported
# (see http://bugs.ruby-lang.org/issues/show/2509).
if key.respond_to?(:clone)
key = key.clone
key.freeze if key.respond_to?(:freeze)
end
key
end现在,谈一些更重要的事情。内部人员提出了一个合理的假设,即new是一种工厂方法。然而,假设[]是一种工厂方法是不太合理的。当然,Struct也是如此,也许其他许多类也是如此,但不一定总是如此。我更希望找到一种方法来明确工厂方法的名称(S),这样我就可以控制哪些方法由内部人员包装。仍然应该有一种简单、默认的方法来使用封装new的内部器,但是也许还有另一种方法可以让您指定要包装的方法。
https://codereview.stackexchange.com/questions/36470
复制相似问题