在Ruby中防止重复的对象

这不完全是单身,但它很接近,所以我认为这很常见。 我有一个类(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-]编程技巧,所以如果已经有一个完整的方法来完成这个工作,我就不会感到惊讶了。


  • 您可以在您的对象中重写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只有一个实例,这通常比你提出的模式少得多。

    你仍然需要实现storelookup位,并且没有什么比你的类中的HashArray更好。

    你想考虑将你存储在你的类中的东西包装在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
    
    链接地址: http://www.djcxy.com/p/95433.html

    上一篇: Prevent duplicate objects in Ruby

    下一篇: About class definition in Ruby