В Ruby есть способ перегрузить конструктор инициализации?


в Java можно перегружать конструкторы:

public Person(String name) {
  this.name = name;
}
public Person(String firstName, String lastName) {
   this(firstName + " " + lastName);
}

есть ли способ в Ruby достичь того же результата: два конструктора, которые принимают разные аргументы?

6 61

6 ответов:

ответ и да и нет.

вы можете достичь того же результата, что и на других языках, используя различные механизмы, включая :-

  • значения по умолчанию для Аргументов
  • списки переменных аргументов (оператор splat)
  • определение аргумента в виде хэша

фактический синтаксис языка не позволяет определить метод дважды, даже если аргументы разные.

учитывая три вышеперечисленных варианта могут быть реализованы в вашем примере следующим образом

# 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"] + " " + args["lastName"] unless args["lastName"].nil?
    @name = name
  end
end

class Person
  def initialize(*args)
    #Process args (An array)
  end
end

вы часто будете сталкиваться со вторым механизмом в коде Ruby, особенно в Rails, поскольку он предлагает лучшее из обоих миров и позволяет некоторым синтаксическим сахарам создавать красивый код, особенно не заключая переданный хэш в фигурные скобки.

этой wikibooks link обеспечивает еще некоторое чтение

Я склонен делать

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 Person
  def initialize(name, lastName = nil)
    name = name + " " + lastName unless lastName.nil?
    @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

можно использовать 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')

Я обычно делаю:

class Person
  attr_reader :name
  def initialize(first: nil, last: nil)
    @name = [first, last].compact.join(' ')
  end
end

Person.new(first: 'ya').name
# => "ya"

Person.new(first: 'ya', last: 'ku').name
# => "ya ku"