【问题标题】:`alias_method` a private method`alias_method` 一个私有方法
【发布时间】:2015-08-13 08:46:13
【问题描述】:

我有一个类公开两个接口方法client_optionsuser_options,在这个祖先级别,它们等价于default_options。我不希望其他开发者直接实现default_options,因此它是私有的。

class Foo
  def client_options
    default_options
  end
  def user_options
    default_options
  end

  private
    def default_options
      { foo: :bar }
    end
end

为了节省一些代码行,我想给方法起别名:

class Foo
  alias_method :client_options, :default_options
  alias_method :user_options, :default_options

  private
    def default_options
      { foo: :bar }
    end
end

alias_method 只给公共方法起别名。

我找到了如何为 this blog 上的私有方法设置别名:

class Foo
  def default_options
    { foo: :bar}
  end

  private :default_options
  alias_method :client_options, :default_options
  public :client_options
end

但是,它有点不可读。

是否有更直接的解决方案来给私有方法取别名?

【问题讨论】:

  • 如果我要实现Foo 子类,我会很感激明确的方法定义。使用alias_method 可能会节省一两行,但它会使您的课程更难理解。
  • 在我看来,如果我从字面上计算代码行数,那么每个答案都是更多行(或最多少 1 行),只需像你一样编写第一个公共方法并为第二个加别名。由于这也比任何更复杂的建议更具可读性,为什么不这样做呢?

标签: ruby alias-method


【解决方案1】:

别名,然后私有化:

alias_method :client_options, :default_options
alias_method :user_options, :default_options
private :default_options

或者,你是否非常了解这个“剪刀规则”:

%i(client_options user_options).each do |m|
  define_method m { default_options }
end

或者创建自己的alias_method 类似方法

  module AliasPrivateMethod
    def alias_private_method_to_interface(name, original_name)
      define_method(name) do |*args, &block|
        send(original_name, *args, &block)
      end
    end
  end

  class Foo
    extend AliasPrivateMethod
    alias_private_method_to_interface(:client_options, :default_options)
    private
      def default_options
        { foo: :bar }
      end
  end

  foo = Foo.new
  foo.public_methods(false) # => [:client_options]
  foo.client_options        # => { foo: :bar }

【讨论】:

  • 嗨,谢谢您的回答,但这与我在问题中发布的内容相同
  • 真的吗?可能SO向我展示了问题的丑陋版本,但我看不到已发布。那么这种方法有什么问题呢?
  • 这是一种有效的方法我并不是说这只是我在寻找一种尊重“剪刀规则”的解决方案....有趣的是,我无法在谷歌上搜索任何关于此规则的文章,但是Robert C. Martin(Clean Coders 视频的创作者)正在谈论它。这是过去的一条规则,您尝试将公共方法/接口方法保留在代码顶部,将私有方法保留在下面。当您将私有方法粘贴在关键字 private 下方时,Ruby 很好地实现了这一点。所以想象一下,如果我的班级有更多私有方法,它们低于私有,但default_options 必须高于私有。
  • 希望我有道理,我运行允许的评论大小来解释它:)
  • @equivalent8 你的最后一个例子也不遵守这条规则。
【解决方案2】:

我发现一个不错的替代方法是将私有方法委托给self

require 'forwardable'
class Foo
  extend Forwardable
  def_delegator :self, :default_options, :client_options
  def_delegator :self, :default_options, :user_options

  private
    def default_options
      { foo: :bar }
    end
end

f = Foo.new
f.client_options 
# => { foo: :bar }

【讨论】:

    【解决方案3】:

    如何实现要隐藏在前置模块中的方法?

    module ProtoFoo
      protected
        def default_options
          {foo: :bar}
        end
    end
    
    class Foo
      prepend ProtoFoo
      def client_options; default_options end
      def user_options; default_options end
    end
    

    即使用户在Foo 中覆盖default_options,也不会生效。

    如果你在暴露的东西之后坚持写隐藏的东西,你可以这样做:

    class Foo
      def client_options; default_options end
      def user_options; default_options end
    end
    
    module ProtoFoo
      def default_options
        {foo: :bar}
      end
    end
    Foo.prepend ProtoFoo
    

    【讨论】:

      猜你喜欢
      • 2020-08-03
      • 2012-10-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-10-01
      • 1970-01-01
      • 1970-01-01
      • 2021-08-31
      相关资源
      最近更新 更多