在Java中,您可以重载构造函数:
public Person(String name) {
this.name = name;
}
public Person(String firstName, String lastName) {
this(firstName + " " + lastName);
}
Ruby中是否有办法实现相同的结果:两个带有不同参数的构造函数?
在Java中,您可以重载构造函数:
public Person(String name) {
this.name = name;
}
public Person(String firstName, String lastName) {
this(firstName + " " + lastName);
}
Ruby中是否有办法实现相同的结果:两个带有不同参数的构造函数?
Answers:
答案是是和不是。
您可以使用多种机制来获得与其他语言相同的结果:
即使参数不同,该语言的实际语法也不允许您两次定义一个方法。
考虑到以上三个选项,可以通过以下示例实现
# As written by @Justice
class Person
def initialize(name, lastName = nil)
name = name + " " + lastName unless lastName.nil?
@name = name
end
end
class Person
def initialize(args)
name = args["name"]
name = name + " " + args["lastName"] unless args["lastName"].nil?
@name = name
end
end
class Person
def initialize(*args)
#Process args (An array)
end
end
您将在Ruby代码中经常遇到第二种机制,特别是在Rails中,因为它提供了两个方面的优势,并且允许一些语法糖来生成漂亮的代码,尤其是不必将传递的哈希值括在花括号中。
这维基链接提供了更多的阅读
我倾向于做
class Person
def self.new_using_both_names(first_name, last_name)
self.new([first_name, last_name].join(" "))
end
def self.new_using_single_name(single_name)
self.new(single_name)
end
def initialize(name)
@name = name
end
end
但是我不知道这是否是最好的方法。
class StatementItem
attr_reader :category, :id, :time, :amount
def initialize(item)
case item
when Order
initialize_with_order(item)
when Transaction
initialize_with_transaction(item)
end
end
def valid?
!(@category && @id && @time && @amount).nil?
end
private
def initialize_with_order(order)
return nil if order.status != 'completed'
@category = 'order'
@id = order.id
@time = order.updated_at
@amount = order.price
end
def initialize_with_transaction(transaction)
@category = transaction.category
@id = transaction.id
@time = transaction.updated_at
@amount = transaction.amount
end
end
您可以将double splat运算符 **
与方法内部的逻辑或(双管道)结合使用||
,initialize
以达到相同的效果。
class Person
def initialize(**options)
@name = options[:name] || options[:first_name] << ' ' << options[:last_name]
end
end
james = Person.new(name: 'James')
#=> #<Person @name="James">
jill_masterson = Person.new(first_name: 'Jill', last_name: 'Masterson')
#=> #<Person @name="Jill Masterson">
但是,如果Person
创建的新内容不带first_name
,则添加<<
操作将失败NoMethodError: undefined method '<<' for nil:NilClass
。这是一种initialize
处理这种情况的重构方法(strip
如果排除了任何一个选项,则用于删除空格)。
class Person
def initialize(**options)
@name = options[:name] || [ options[:first_name] , options[:last_name] ].join(' ').strip
end
end
goldfinger = Person.new(last_name: 'Goldfinger')
#=> #<Person @name="Goldfinger">
oddjob = Person.new(first_name: 'Oddjob')
#=> #<Person @name="Oddjob">
实际上,此方法可以处理Person.new
不带参数或使用意外键的调用,以将@name
设置为空字符串的新实例返回:
nameless = Person.new
#=> <#Person @name="">
middle_malcom = Person.new(middle_name: 'Malcom')
#=> <#Person @name="">
您可以使用konstructor gem在Ruby中声明多个构造函数并模仿重载:
class Person
def initialize(name)
@name = name
end
konstructor
def from_two_names(first_name, last_name)
@name = first_name + ' ' + last_name
end
end
Person.new('John Doe')
Person.from_two_names('John', 'Doe')
Person.new(:first_name => "...", :last_name => "...")
方法。出于某种原因,我并没有想到要使用它,但这确实回答了我的问题。