我有一个模块,可以生成所需格式的电话号码。
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
答案 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 method或converting your module to a class也是合理的选择。自然,您的里程和风格品味可能会有所不同。