2012-06-18 51 views
2

我想要類似下面的東西,但希望它可以重用於不同的類。如何創建一個存儲實例的類?

我該如何重構這段代碼,只需要很少的努力就可以將它包含在一個類中,並且每當有新的被調用時,這個類將自動收集實例?

我已經嘗試了各種各樣的重寫新的或初始化的東西,但不能得到發生的魔法。

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請求,否則將繼續存在?

回答

4

修訂ANSWER

我如果您希望在請求期間保持它可用,沒有以前的答案可以做到這一點。只有在請求響應週期保持它提供的解決方案是使用一個線程局部是在控制器的方法分配,例如:

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 
+0

我從那開始,但我讀到,你可能會得到尚未GC'd的舊對象。任何人都可以確認嗎? – Tim

+0

是的,那是可能的。你想做什麼?你爲什麼想要訪問這些實例?如果你解釋**你想要做什麼,然後可能會有更好的**如何**,那就簡單多了。 –

+0

這是否意味着如果我使用帶有Passenger的Rails,新連接將共享實例或者是等同於啓動另一個進程的新連接? – Tim

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 
+0

看起來你失蹤的代碼。 – Tim

+0

@Tim對不起,在進入響應時被拉開了。 – Anil

+0

@DaveNewton答案現在就可以開始檢查了!我相信你可以幫助改進它。謝謝。 – Anil

相關問題