0

在我的项目Bar中,我有这个类Foo,它的实例代表唯一的、命名的真实世界对象。对这些实例的引用分散在我项目中的数据结构周围,而且我决定让它们通过它们的名称访问。为此,类 Foo 本身会跟踪其实例,例如

module Bar
  class Foo
    attr_reader :name

    def initialize( name )
      @name = name
    end

    def self.new *args, &block
      new_instance = super
      n_i_name = new_instance.name
      ( @instances ||= {} ).merge! new_instance => n_i_name
      return new_instance
    end

    def inspect; "Foo instance #{name}" end
  end
end

现在这是一种常见的模式。通常,要访问实例,可以在以下位置建立公共类方法Foo

class << Bar::Foo
  def instance( i )
    case i
    when self then i
    else @instances.rassoc( i ).first end
  end
end

i = Bar::Foo.new "John Smith"
#=> Foo instance John Smith
i.object_id
#=> 68997470
Bar::Foo.instance( "John Smith" ).object_id
#=> 68997470

但问题是,模块下有命名实例的类比类Bar,例如Bar::BazBar::Quux等等,它们需要Foo通过名称访问实例和彼此。所以我认为保持这些不同类通过名称访问彼此实例的方式的顺序是Bar模块本身的责任,我在其中创建了公共模块方法:

module Bar
  # Foo method blah blah blah...
  def self.Foo( i ); Foo.instance i end

  # Baz method blah blah blah...
  def self.Baz( i ); Baz.instance i end

  # Quux method blah blah blah...
  def self.Quux( i ); Quux.instance i end
end

每当类Foo, Baz,Quux相互引用时,它们都会使用Bar.Foo( "John Smith" )样式调用,这使得也可以通过它们的唯一名称来引用这些实例。现在我的问题是,这对我来说仍然不是 100% 的犹太教。当我运行rdocBar模块、公共类方法创建文档#Foo#Baz#Quux将其添加到文档中。但这些并不是真正打算成为用户界面的一部分。所以我有以下选项,每个选项都有问题:

  1. 在用户界面中包括#Foo, #Baz, 。问题:用户并没有那么迫切地需要它们;我的设计意图不是让它们出现在 UI 中。#Quux

  2. 向它们添加# :nodoc:指令以防止rdoc记录它们。问题:感觉不对。它不喜欢Bar.Foo和朋友被排除在用户界面之外。感觉更像是它们仍然是 UI 的一部分,但没有记录,是秘密的。我不想要那个。

  3. 使用 . 将它们声明为私有#private_class_method。但是,即使实例#Foo, #Baz,#Quux在正常操作期间通过名称相互访问,它们也必须使用Bar.send :Foo, "John Smith"样式。

问题:选项 3. 似乎危害最小。但是,它仍然不完美。理想情况下,我希望方法Bar.Foo, Bar.Baz,Bar.Quux以这样的方式受到保护,这些人可以通过简单地调用来通过名称相互调用Bar.Foo "John Smith",而用户必须使用Bar.send :Foo, "John Smith",并且这些模块方法没有为用户记录。我还需要哪些其他选择(如果有的话)来实现这种状态?有没有办法选择性地允许某些类随意使用其他人的私有方法?另外,我对受保护的类方法没有经验,这可能是一个解决方案吗?感谢您花时间阅读本文。

4

1 回答 1

1

看看Understanding private methods in Ruby and search SO for private/protected,有很多资料要阅读。

受保护的类方法:

class Foo
    class << self
        def prot
            puts "self.prot"
        end
        protected :prot
    end
...

Bar::Foo.prot #=> protected method `prot' called for Bar::Foo:Class (NoMethodError)
于 2012-12-09T06:33:50.587 回答