2
class Event

    @event_list = {}

    attr_reader :name, :value

    def initialize(name, value)
      @name  = name
      @value = value
    end

    def to_s
      "#{@value}"
    end

    class << self

      def event_list
          @event_list
      end

      def event_list=(value); end

      def register_event(name, value)
          @event_list[name] = Event.new(name, value)
      end

      def registered_events
          event_list
      end
    end
end

在上面的代码片段中,我可以使用 Event.event_list 访问@event_list,有趣的是我可以从外部修改这个变量

Event.event_list[:name] = "hello"
Event.event_list  # => { :name => 'hello' }

我怎样才能避免这种情况?,我不想从外部修改@event_list。

4

4 回答 4

1

据我所知,您无法阻止外部代码修改 Ruby 中的实例变量。即使您不使用它attr_readerattr_writer仍然可以使用Object#instance_variable_set. Ruby 没有私有变量(或常量),只有礼貌地要求您不要修改的变量。

如果您不定义event_list=,则将其视为@event_list私有变量的指示。这是您的问题的解决方案。

然后是可变对象的问题。由于 Ruby 中几乎所有的对象都是可变的,通常如果你能得到一个对象的引用,那么你就可以改变它。

这可以通过Object#freeze阻止对象被修改来解决。不幸的是,这意味着即使您也无法修改它。

Ruby 根本不适合锁定事物。这种开放性是您可能需要学习使用的语言的核心部分。

于 2015-04-22T18:06:12.540 回答
1

正如其他人所说,只需将方法设为私有:

class Event
    @event_list = {a: 'dog'}
    class << self
      def pub_event_list
        @event_list
      end  
      def pub_event_list=(other)
        @event_list=other
      end  
      private
      def event_list
        @event_list
      end
      def event_list=(value)
        @event_list = value
      end
    end
end

Event.event_list
  #=> NoMethodError: private method `event_list' called for Event:Class

Event.pub_event_list
  #=> {:a=>"dog"} 

Event.event_list= {b: 'cat'}
  #=> #NoMethodError: private method `event_list=' called for Event:Class

Event.pub_event_list= {b: 'cat'}
  #=> {:b=>"cat"} 
于 2015-04-22T19:01:44.760 回答
0

您正在定义def event_list您的单例,它提供对变量的访问。将该方法设为私有

编辑:

当您声明@event_list它在您的单例方法中具有范围时。

class Event
  @event_list = {}

  class << self
    def event_list
      # scoped from above
      @event_list
    end
  end
end

Event.event_list #=> {}

要删除访问权限,只需将方法设为私有:

class Event
  @event_list = {}

  class << self
    private

    def event_list
      # scoped from above
      @event_list
    end
  end
end

Event.event_list #=> NoMethodError: private method `event_list' called for Event:Class
于 2015-04-22T17:56:56.977 回答
0

这是我现在做的,我不知道这是否是一个好的解决方案

class Event

  @event_list = {}

  attr_reader :name, :value

  def initialize(name, value)
    @name  = name
    @value = value
  end

  def to_s
    "#{@value}"
  end

  class << self
    def register_event(name, value)
      @event_list = @event_list.merge(name => Event.new(name, value))
    end

    def registered_events
      @event_list.freeze
    end
  end
end

现在我可以访问@event_list 而不让其他人修改。

于 2015-04-23T09:55:07.817 回答