不要在每个类方法中都使用self,也不在ruby中使用单例模型

时间:2018-12-18 21:03:41

标签: ruby-on-rails ruby singleton

我在编写漂亮代码方面遇到了麻烦。基本上,如果我定义了一个根本不会实例化的类,我会做这样的事情:

class Foo
  def self.bar
    # Do something
  end
end

但是这种语法使我感到困扰(必须在每种方法中放入self.),因此单例解决了我的问题:

class Foo
  class << self
    def bar
      # Do something, but in better code
    end
  end
end

在两种方式下,我都可以做Foo.bar并且可以做点事,但是第一个看起来不太好,在第二个中,我仍然不了解单例的确切工作方式,因此最好小心而不要使用它。

所以,最后...我想问的是:除了上述内容,还有其他方法可以Foo.bar吗?

2 个答案:

答案 0 :(得分:1)

这是我在评论中提到的深奥元编程技术的示例:

module Foo
  instance_eval do
    def bar
      'baz'
    end
  end
end

现在调用新方法:

Foo.bar
=> 'baz'

instance_eval的用法是unintuitive,因为它是用于定义类方法的,而class_eval是用于实例方法的。

Cary提到的技术也有类似的方法(尽管他使用define_method来代替实例方法,而define_singleton_method是用于类方法):

module Foo
  define_singleton_method(:bar) do
    'baz'
  end
end

调用该方法的原理相同:

Foo.bar
=> 'baz'

但是,这些都是高级技巧,您将永远不会以这种方式使用它们,因为完成相同任务的标准方法要简单得多(并且您在问题中举了两个例子)。如果您尝试以这种方式定义所有的类方法,那将是丑陋的,重复性的,并使阅读它的任何人感到困惑。

所示的技术通常由代码外部在已定义的模块/类中使用,因此您可以在外部进行操作而不必直接修改其源代码,有时称为{{3} }。

例如,如果模块没有定义方法:

module Foo
end

您可以在其他任何地方的代码中用Foo.instance_eval {}Foo.define_singleton_method(:bar) {}表示,此后将适用于Foo。当您想挫败Foo尝试monkey patching的作者时,这很有用。

如果我不清楚,这里显示的示例是您应该做的。当需要动态更改类/模块时使用它们。那不是你所描述的。

答案 1 :(得分:1)

engineersmnky in the comments已经提到过)

您可以使用包含您的类方法的模块扩展您的类(该模块可以嵌套在您的类中):

class Foo
  module ClassMethods
    def bar
      # Do something
    end
  end

  extend ClassMethods
end

您还可以将其移到类之外,甚至移至其自己的文件中(这在结构上或在许多 类方法中都非常有用):

# foo/class_methods.rb
class Foo
  module ClassMethods
    def bar
      # Do something
    end
  end
end

# foo.rb
class Foo
  extend ClassMethods
end

通过extend定义的方法甚至可以在基类中覆盖:

class Foo
  module ClassMethods
    def bar
      123
    end
  end
end

class Foo
  extend ClassMethods

  def self.bar
    super * 2
  end
end

Foo.bar #=> 246

如果要在使用同一模块扩展多个类时想添加自定义功能(这是共享类方法),这将特别有用。