这不是一个单身人士,但它很接近,所以我想这很常见。我有一个类(Foo),其中的实例对应于具有唯一ID的外部数据结构。我想确保没有两个Foo实例可以具有相同的ID - 如果使用相同的id值调用构造函数,使用该ID调用原始 Foo实例,并且只更新所有其他值。换句话说,比如:
class Foo
def initialize(id, var1, var2)
if Foo.already_has? id
t = Foo.get_object(id)
t.var1 = var1
t.var2 = var2
return t
else
@var1 = var1
@var2 = var2
end
end
我可以想到两种方法:
我可以将Foo的所有实例数组保存为类级变量,然后在初始化方法结束时调用foo_instances.push(self)。这让我觉得很难看。
我相信Ruby已经跟踪某个数组中每个类的实例 - 如果是这样,这是否可以访问,它会比#1更好吗?
??? (Ruby似乎支持一些灵活的[meta-]编程技巧,所以如果已经有一种整洁的方法我不会感到惊讶。
答案 0 :(得分:2)
您可以覆盖对象中的Foo.new
,并在那里执行任何操作:
class Foo
def self.new(id, var1, var2)
return instance if instance = self.lookup
instance = self.allocate
instance.send :initialize, var1, var2
return self.store(instance)
end
end
显然,您也可以使用不同的类方法来获取对象;将initialize
方法设为私有,以帮助阻止意外分配。
这样你每个ID只有一个实例,这通常比你提出的模式痛苦得多。
你仍然需要实现store
和lookup
位,并且没有什么比你班级中的Hash
或Array
更好的了。
您想要考虑将您存储在类中的内容包装在WeakRef实例中,但仍然返回真实对象。这样,该类可以强制执行唯一性,而不会限制所使用的每个ID始终保留在内存中。
这不适合你的每个版本的情况,但对某些人来说肯定是这样。一个例子:
# previous code omitted ...
return store(instance)
end
def self.store(instance)
@instances ||= {}
@instances[instance.id] = WeakRef.new(instance)
instance
end
def self.lookup(id)
@instances ||= {}
if weakref = @instances[id] and weakref.weakref_alive?
return weakref.__getobj__ # the wrapped instance
else
return nil
end
end