Предотвращение дублирования объектов в Ruby - PullRequest
1 голос
/ 28 января 2012

Это не совсем синглтон, но он близко, так что я думаю, что это обычное дело. У меня есть класс (Foo), в котором экземпляры соответствуют внешним структурам данных с уникальными идентификаторами. Я хочу убедиться, что никакие два экземпляра Foo не могут иметь одинаковый идентификатор - если конструктор вызывается с одинаковым значением идентификатора, экземпляр 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 поддерживает некоторые хитрые [мета-] приемы программирования, поэтому я не удивлюсь, если уже есть аккуратный способ сделать это, которого мне не хватает.

1 Ответ

2 голосов
/ 28 января 2012

Вы можете переопределить 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 закрытым, чтобы предотвратить случайное распределение.

Таким образом, у вас будет только один экземпляр с каждым идентификатором, что, как правило, гораздо менее болезненно, чем предлагаемый вами шаблон.

Вы по-прежнемунеобходимо реализовать биты store и lookup, и нет ничего лучше, чем Hash или Array в вашем классе, чтобы сделать это с.

Вы хотите подумать о переносевещи, которые вы храните в своем классе в экземпляре WeakRef , но при этом возвращаете реальный объект.Таким образом, класс может обеспечивать уникальность, не ограничивая также, чтобы каждый когда-либо использовавшийся идентификатор оставался в памяти постоянно.

Это подходит не для каждой версии ваших обстоятельств, но, безусловно, для некоторых.Пример:

  # 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...