【问题标题】:Prevent duplicate objects in Ruby防止 Ruby 中的重复对象
【发布时间】:2012-01-28 04:49:48
【问题描述】:

这不完全是单例,但很接近,所以我想这很常见。我有一个类 (Foo),其中实例对应于具有唯一 ID 的外部数据结构。我想确保没有两个 Foo 实例可以具有相同的 ID - 如果使用相同的 id 值调用构造函数,则具有该 ID 的 original 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

我可以想到两种方法来做到这一点:

  1. 我可以将 Foo 的所有实例的数组保留为类级变量,然后在初始化方法结束时调用 foo_instances.push(self)。这让我觉得有点丑陋。

  2. 我相信 Ruby 已经在某个数组中跟踪每个类的实例 - 如果是这样,这是否可以访问,它会比 #1 更好吗?

  3. ??? (Ruby 似乎支持一些巧妙的 [元] 编程技巧,所以如果我已经缺少一种整洁的方法,我不会感到惊讶。

【问题讨论】:

    标签: ruby singleton


    【解决方案1】:

    您可以在您的对象中覆盖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
    

    【讨论】:

    • 感谢您介绍我分配 - 我没有意识到存在。不过,对于查找,有没有比手动创建/管理实例数组更好的方法?
    • 不。好吧,也许是Hash,但这并没有什么不同。
    • 实际上,等等——你几乎肯定想在该数组中的对象周围包装一个来自标准库的WeakRef——这样它们就不会永远逗留:ruby-doc.org/stdlib-1.8.7/libdoc/weakref/rdoc/WeakRef.html
    • 如果一个对象被删除,并且在再次调用构造函数之前没有发生垃圾收集怎么办?我是否需要在每次调用 .new 开始时调用 Objectspace.garbage_collect?
    • 我更新了答案,但简而言之:不,不要对垃圾收集做任何事情。在内部保留一个弱引用,但将真实对象返回给调用者,以便他们保持其活动状态。
    猜你喜欢
    • 2021-08-02
    • 1970-01-01
    • 2017-07-28
    • 2020-12-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-05
    • 1970-01-01
    相关资源
    最近更新 更多