如何创建存储实例的类?

时间:2012-06-18 02:41:19

标签: ruby

我想要类似下面的东西,但希望它可以重复使用不同的类。

如何重构这段代码,所以只需要很少的努力就可以将它包含在一个类中,并且只要调用new,该类就会自动收集实例?

我尝试了各种各样的事情,例如重写新的或初始化但却无法让魔法发生。

   class Person      
      @@people_instances = []

      def initialize
         @@people_instances << self
      end

      def self.instances
         @@people_instances
      end

   end


People.new
People.new
Poople.instances

 => [#<Person:0x000001071a7e28>, #<Person:0x000001071a3828>] 

在下面的一些反馈之后,我认为答案不是将实例放在一个类变量中,因为它将永远留在内存中。 Rails缓存也不太合适,因为我不需要实例持久化。

以下代码使用类实例变量而不是类变量。

http://www.dzone.com/snippets/class-variables-vs-class

class Employee
  class << self; attr_accessor :instances; end
  def store
    self.class.instances ||= []
    self.class.instances << self
  end
  def initialize name
    @name = name
  end
end
class Overhead < Employee; end
class Programmer < Employee; end
Overhead.new('Martin').store
Overhead.new('Roy').store
Programmer.new('Erik').store
puts Overhead.instances.size    # => 2
puts Programmer.instances.size  # => 1

这些实例变量是否对每个rails请求都是唯一的,还是会持续存在?

2 个答案:

答案 0 :(得分:4)

更新的答案

如果您希望仅在请求期间保持可用,则之前答案的可以执行此操作。仅在请求 - 响应周期期间保持其可用的解决方案是使用在控制器方法中分配的线程本地,例如:

class YourController < ApplicationController

  around_filter :cache_objects

  protected

  def cache_objects
    Thread.current[:my_objects] = ['my-object', 'my-other-object']
    yield
    ensure
      Thread.current[:my_objects]
  end

end

然后,在需要它的代码中,你只需执行Thread.current[:my_objects]并做任何你想做的事情。您需要使用 around_filter ,因为您的Web框架或服务器结构可能会尝试重用线程,唯一真正的解决方案是在请求完成后清理它们以避免内存泄漏。


OLD ANSWER

不确定您要做什么,但您可以使用ObjectSpace轻松选择每个班级的实例:

ObjectSpace.each_object(String) { |s| puts(s) }

如果你需要的是数据库缓存,只需使用Rails缓存,加载这些对象一次,然后将它们保存在缓存中。使用Rails缓存时,您只需将对象发送到缓存:

Rails.cache.write( "my_cached_objects", [ 'first-object', 'second-object' ] )

然后把它们带到其他地方:

Rails.cache.fetch("my_cached_objects") do 
  # generate your objects here if there was a cache miss
  [ 'first-object', 'second-object' ]
end

正如您所看到的,您甚至不必调用cache.write,您只需使用fetch,每当有缓存未命中时,将调用给定的块并创建对象。

您可以阅读有关铁路缓存here的更多信息,您可以看到ActiveSupport::Cache::Store here支持的所有方法。

另一种不使用ObjectSpace但仍使用丑陋解决方案的方法,现在使用alias_method

module Counter

  def self.included( base )
    base.extend(ClassMethods)
    base.class_eval do
      alias_method :initialize_without_counter, :initialize
      alias_method :initialize, :initialize_with_counter
    end
  end

  def count_class_variable_name
    :"@@#{self.class.name.downcase}_instances"
  end

  def initialize_with_counter( *args )
    unless self.class.class_variable_defined?(count_class_variable_name)
      self.class.class_variable_set(count_class_variable_name, [])
    end

    self.class.class_variable_get(count_class_variable_name) << self
    initialize_without_counter(*args)
  end

  module ClassMethods

    def all_instances
      class_variable_get(:"@@#{name.downcase}_instances")
    end

  end

end


class Person

  def initialize
    puts 'new person'
  end

  include Counter

end

p1 = Person.new
p2 = Person.new
p3 = Person.new

puts Person.all_instances.size

答案 1 :(得分:2)

LIB / keeper.rb

def initialize
  instance_eval "@@#{self.class.to_s.downcase}_instances ||= []"
  instance_eval "@@#{self.class.to_s.downcase}_instances << self"
end

def self.instances
  return class_eval "@@#{self.to_s.downcase}_instances"
end

person.rb

class Person
  eval File.open('./lib/keeper.rb','rb').read
end

然后这个有效:

Person.new
Person.new
Person.instances