在Ruby中逐个方法调用

时间:2018-08-24 18:22:47

标签: ruby module

我有一个模块,可以生成所需格式的电话号码。

module PhoneNumber
  def self.prefix
    '+'
  end
  def self.country
    rand(1..9).to_s
  end
  def self.code
    rand(100..999).to_s
  end
  def self.number
    rand(1000000..9999999).to_s
  end
end

我如下使用它。 或作为格式字符串"#{}#{}"

phone_number = PhoneNumber.prefix +
               PhoneNumber.country +
               PhoneNumber.code +
               PhoneNumber.number

我想以此方式重写模块主体, 这样我就可以以点分格式使用它。

PhoneNumber.prefix.code.number

3 个答案:

答案 0 :(得分:6)

我同意托德的观点,你不应该这样做。对于阅读代码的人(包括将来的您自己)来说,实现和混淆起来会很尴尬,因为这不是编写您正在谈论的操作的典型方法。

也就是说,如果您确实想这样做,则需要提供一个名为prefix的方法,该方法返回另一个具有方法code的对象,依此类推,沿着链条存储状态并在最后合并字符串。如果要交换订单,情况将变得更加复杂。

强烈建议您使用一种看起来像这样的方法:

PhoneNumber.build(:prefix, :code, :number)

答案 1 :(得分:3)

要链接方法,基本上应该不断从要链接的所有方法中返回self

module PhoneNumber
  @number = ''
  def self.prefix
    @number << '+'
    self
  end
  def self.country
    @number << rand(1..9).to_s
    self
  end
  def self.code
    @number << rand(100..999).to_s
    self
  end
  def self.number
    @number << rand(1000000..9999999).to_s
    self
  end
  def self.to_s
    @number
  end
end

puts PhoneNumber.prefix.code.number
#⇒ +9065560843

请注意最后一步的显式#to_s实现,因为您可能希望将字符串作为结果,而不是类本身。

此实现有一个小故障:由于只有一个共享的@number,因此几乎不可重用,因此最好将所有方法都作为实例方法来做:

class PhoneNumber
  def initialize
    @number = ''
  end
  def prefix
    @number << '+'
    self
  end
  def country
    @number << rand(1..9).to_s
    self
  end
  def code
    @number << rand(100..999).to_s
    self
  end
  def number
    @number << rand(1000000..9999999).to_s
    self
  end
  def to_s
    @number
  end
end

puts PhoneNumber.new.prefix.code.number
#⇒ +6117160297

现在它可用于后续呼叫。

答案 2 :(得分:1)

将字符串构造包装为类方法

“点分格式”实际上是一组链接方法。通过将每个类方法的输出附加到方法链中的String上,您可以想像地完成与尝试要做的事情 ,但我认为这是一种脆弱且不适合的OOP设计。

在语义级别上,链中的每个方法都意味着“对前一个方法的返回值执行x。”当您要描述对象的成员或其他类型的初始化时,有更多惯用的方法可以实现。

无需对现有代码进行重大更改,您只需添加PhoneNumber#create类方法即可为您完成繁重的工作。例如:

module PhoneNumber
  def self.create
    [self.prefix, self.country, self.code, self.number].join
  end

  def self.prefix
    '+'
  end

  def self.country
    rand(1..9).to_s
  end

  def self.code
    rand(100..999).to_s
  end

  def self.number
    rand(1000000..9999999).to_s
  end
end

if __FILE__ == $0
  puts PhoneNumber.create
end

加入其他类方法返回的String对象数组是相当惯用的,从语义上讲是明确的,并且回避了更改现有类方法(程序中的其他对象当前可能依赖该类方法)的需要。这可以使变更本地化,这在OOP设计中通常是一件好事。

如您对问题的其他回答所述,

Parameterizing a methodconverting your module to a class也是合理的选择。自然,您的里程和风格品味可能会有所不同。