在ruby中仅在单例中实例化对象一次

时间:2015-05-13 18:45:42

标签: ruby

我最近几天一直在处理这个基于Factory模式的类,你可以在这里注册类,给它们提供唯一的名称,然后使用它们来动态创建对象。我的课看起来像这样:

{
    "languages": [
        {
            "id": 1,
            "language": { "name": "Spanish" },
            "proficiency": {
                "level": "native_or_bilingual",
                "name": "Native or bilingual proficiency"
            }
        },
        {
            "id": 2,
            "language": { "name": "English" },
            "proficiency": {
                "level": "full_professional",
                "name": "Full professional proficiency"
            }
        },
        {
            "id": 3,
            "language": { "name": "Japanese" },
            "proficiency": {
                "level": "elementary",
                "name": "Elementary proficiency"
            }
        }
    ]
}

但是我有一些问题,这些问题出现在我写测试的时候。

  1. 在我所做的module AisisWriter class ClassFactory class << self undef_method :new attr_accessor :registered_objects def register(class_name, klass, params = nil) if !params.nil? && !params.is_a?(Array) raise ArgumentError, "Params must be an array." end if registered?(class_name) raise ArgumentError, "Class name already registered." end @registered_object[class_name] = {:class_name => klass, :params => !params.nil? ? params.flatten : nil} end def registered?(class_name) if @registered_object.nil? return false end @registered_object.include? class_name end def create(class_name, params = nil) if !params.nil? && !params.is_a?(Array) raise ArgumentError, "Params must be an array." end if !registered?(class_name) raise ArgumentError, "Class does not exist in the registered classes." end klass = @registered_object[class_name] if !params.nil klass[:class_name].new(params.flatten) else flass[:class_name].new(*klass[:params]) end end end end end 函数中:
  2. register(...) 这失败是因为@registered_object[class_name] = {:class_name => klass, :params => !params.nil? ? params.flatten : nil} 为零。我如何只初始化一次?在php中我会写一个@registered_object方法,并说如果设置了类实例,不要再设置它,而我们设置类实例时也设置其他只需要设置一次的变量。我会在这里使用getInstance()方法吗?

    1. 关于问题一,我可以在ruby中链接方法吗?所以,如果我需要获取此类的实例,只需将get_instance设置为@registered_object一次,那么我可以这样做:{} ruby​​是否支持这个?
    2. 这里的基础是确保在调用此类时,我们检查AisisWriter::ClassFactory.get_instance.register(...)是否为nil,如果是,则将其设置为@register_object的新实例

      如果有一个更容易的解决方案,我很满意。

2 个答案:

答案 0 :(得分:5)

你可以做到

def registered_object
  @registered_object ||= {}
end

然后拨打registered_object而不是@registered_object

这是一个常见的Ruby习语。这意味着:

  

如果@registered_object是假的,则将其设置为{}。

答案 1 :(得分:0)

如果你想要一个真正的单件工厂,那么Ruby有Singleton module可以帮助你!

您可以像这样定义您的课程:

module AisisWriter
  class ClassFactory
    include Singleton
    attr_accessor :registered_objects

    def initialize
      @registered_object = {}
    end

    def register(class_name, klass, params = nil)
      raise ArgumentError, "Class name already registered." if registered? class_name
      @registered_object[class_name] = {:class_name => klass, :params => params}
    end

    def registered?(class_name)
      @registered_object.key? class_name
    end

    def create(class_name, params = nil)
      raise ArgumentError, "Class does not exist in the registered classes." unless registered? class_name
      klass = @registered_object[class_name]
      klass[:class_name].new *Array(params || klass[:params])
    end
  end
end

这提供了一种#initialize方法,您可以在其中设置所有单例状态,但::new不可调整,如您所料。相反,您使用::instance

然后你就像使用它一样:

AisisWriter::ClassFactory.instance.register(...)
AisisWriter::ClassFactory.instance.create(...)

首次调用#instance时,工厂只会被实例化一次。