Ruby常量是模板方法参数中的默认值吗?

时间:2014-01-14 05:08:08

标签: ruby design-patterns

这确实是一个关于Ruby的问题所以不要介意最初的Java。

我来自Java背景,在该语言中,常见的是看到常量中捕获的默认值。这是一个例子:

public class Foo {

    private static final int DEFAULT_POINTS = 10;

    private final int points;

    public Foo() {
        this.points = DEFAULT_POINTS;
    }

    public Foo(Integer initialPoints) {
        this.points = initialPoints;
    }

    public int getPoints() {
        return points;
    }

}

我的问题是在Ruby中做类似的事情。以上内容可以翻译成红宝石,如下所示:

class Foo

  attr_reader :points

  def initialize(options={})
    @points = options[:points] || default_points
  end

  def default_points
    10
  end

end

暂时忽略我可以在构造函数内联中指定默认值。让我们假装它是一个消息发送,因为我最终可能想做一些子类。

我的问题是:在Java中,我在类的顶部捕获常量中的默认值。在Ruby中是否有类似的概念,或者将它作为方法内部的返回值是否常见?

3 个答案:

答案 0 :(得分:1)

当然,常量也可以在Ruby中用于这样的事情。我见过很多例子。

答案 1 :(得分:1)

是的,你可以这样做:

class Foo

  attr_reader :points

  DEFAULT_POINTS = 10

  def initialize(options={})

    @points = options[:points] || Foo::DEFAULT_POINTS       

  end

end

puts Foo.new.points # => 10

答案 2 :(得分:1)

Ruby从perl继承了它的设计理念,它基本上归结为有多种方法来做事情,所以你(理论上)可以用最容易理解的方式表达自己。

根据您的使用案例和偏好,有几种方法可以做到这一点毫不奇怪

方式1,幻数,只要上下文清晰且您不在应用中的其他地方使用默认点,这就完全可以了(更是如此,这是首选)(请参阅{ {3}})

def initialize(options)
  points = options[:points] || 10
end

一旦你开始在应用程序的其他地方重用默认点,它就是重构时间,并且有几种方法,每种方法都有自己的优点和缺点

方式2,常数,好处是它可以从任何地方清晰地访问(通过Foo::DEFAULT_POINTS),缺点是它不是OOP并且在子类中覆盖它不起作用预期

DEFAULT_POINTS = 10

def initialize(options)
  points = options[:points] || DEFAULT_POINTS
end

方式3& 4,实例方法vs类方法,你在你的例子中做了实例方法,类方法可以这样工作:

def self.default_points
  10
end

def initialize(options)
  points = options[:points] || self.class.default_points
end

这种方法的改进(一旦self.class self.class self.class self.class垃圾邮件开始传达给你,rubyists对这些事情有点强迫症)就是从实例委托to class,例如rails:

def self.default_points
  10
end
delegate :default_points, to: 'self.class'

def initialize(options)
  points = options[:points] || default_points
end

使用类方法和实例方法来做事情有利有弊,最好的资源来了解它们是什么http://thedailywtf.com/Articles/Soft_Coding.aspx

方式5,私有实例方法 - 当您立即确定默认点将仅在类的上下文中使用而不在外部时,您希望通过类重用它并继承/在子类中重写,

def initialize(options)
  points = options[:points] || default_points
end

private

def default_points
  10
end

请注意,在Ruby中,您仍然可以通过调用foo.send(:default_points)来访问私有方法。一旦你开始在你的代码中发送foo.send(:default_points)垃圾邮件,就会发现某些东西需要重构(要么不需要从课外调用default_points,要么让default_points公开)。< / p>

Ruby方式是编程自由的方式,你可以在运行时重写其他人的类,你可以改变常量的值,你可以调用私有方法...... Ruby不会阻止任何东西,并且具有强大的力量带来很大的责任

基本理念是,如果你不应该在ruby中做某事,你就不应该阻止这样做(警告是,应该=必须没有)这与Java完全一致你可能习以为常的方式。

缺点是坏人会编写错误的代码,好处是,如果你真的需要在0.01%的时间内做一些特别的事情,你能够做到这一点(将一个猴子补丁应用到oracle驱动程序直到你的pull请求被释放是一个很好的例子。)

<强>更新

使用其他方式时要记住的一件事2:避免一次又一次地实例化对象(尤其是重物),请参阅http://blog.codeclimate.com/blog/2012/11/14/why-ruby-class-methods-resist-refactoring/

此外,http://gavinmiller.io/2013/basics-of-ruby-memoization/