Это выглядит правильно, как печатать утку Руби? - PullRequest
1 голос
/ 26 мая 2011

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

У меня есть три класса: Car, CarHistory и CarServiceHistoryEntry.Третий прост;он содержит все атрибуты, связанные с услугой: дата, пробег, выполненная услуга и т. д. Класс CarHistory выглядит следующим образом:

require_relative 'car_service_history_entry'

class CarHistory
  attr_reader :entries
  def initialize (*entry)
    if entry.size > 1
      @entries = []
    else
      @entries = entry
    end
  end
  def add_service_entry entry
    @entries << entry
  end
  def to_s
    entries_string = ""
    @entries.each {|entry| entries_string << "#{entry.to_s}\n"}
    entries_string
  end
end
  1. В initialize, если класс entry быть проверенным?
  2. В add_service_entry, принимающем типизацию утки (как в аргументе Энди Томаса в "Программировании Ruby"), я бы даже протестировал, можно ли добавить CarServiceHistoryEntry?Разве я не могу просто передать String вместо настройки, а затем добавить CarServiceHistoryEntry в моем модульном тестировании?
  3. Поскольку единственными необходимыми атрибутами CarHistory являются массив entries и to_s метод, я должен просто собрать этот класс все вместе и поместить его в car класс?

Ответы [ 3 ]

1 голос
/ 26 мая 2011

Для 1 и 2 вам нужно ослабить контроль над «строгой типизацией», когда вы переходите на свободно набираемый язык, такой как Ruby.

  • Стоит ли проверять входные аргументы? Традиционный ответ будет да. Альтернативным способом было бы иметь хорошие имена и модульные тесты, которые документируют и определяют, как тип должен работать. Если это работает с другими типами, хорошо .. это дополнительный бонус. Так что если вы передадите несовместимый тип, он будет взорван с исключением, что в большинстве случаев достаточно. Попробуйте и посмотрите, каково это (возможные результаты: освобождение / «Отступление!». Но попытайтесь сделать это честно). Исключения могут быть, если вы разрабатываете открытые API для разделяемых библиотек, в которых правила отличаются. Вам нужно быстро и информативно потерпеть неудачу при неправильном вводе.
  • Что касается того, чтобы забивать car_history в машину - я бы спросил, каковы обязанности вашего класса Car. Если ведение собственной истории является одним из них, вы можете их забить. В будущем, если вы обнаружите множество методов, связанных с историей автомобилей, вы можете снова отменить это решение и снова извлечь тип CarHistory. Используйте принцип SingleResponsibilityPrinciple для принятия обоснованного решения. Это просто ООП - Ruby не ухудшает дизайн объекта.

Фрагмент кода: код может быть более кратким

# just for simplicity, I'm making HistoryEntry a string, it could be a custom type too
class CarServiceHistoryEntry << String
end

class CarHistory
  attr_reader :entries
  def initialize(*history_entries)
    @entries = history_entries
  end

  def add_service_entry(entry)
    @entries << entry
  end
  def to_s
    @entries.join("\n")
  end
end

irb>x = CarHistory.new("May 01 Overhaul", "May 30 minor repairs")
irb>x.add_service_entry("June 12 Cracked windshield")
irb>x.to_s
=> "May 01 Overhaul\nMay 30 minor repairs\nJune 12 Cracked windshield"
1 голос
/ 26 мая 2011

Трудно комментировать отношения класса CarHistory с вашими другими, но я уверен, что вам это станет ясно по мере вашего продвижения.

Несколько ваших методов можно было бы упростить, хотя я должен сказать, что я не понял if в initialize, возможно, это было просто назад и должно было быть > 0.

def initialize *entry
  @entries = entry # if not specified it will be [] anyway
end

def to_s
  @entries.join "\n"
end

И да, Ruby должен быть простым. Вам не нужно засорять ваш код проверками типов во время выполнения. Если код запускает ваши юнит-тесты, вы можете просто объявить победу. Миллионы явных преобразований имеют тенденцию исправлять ошибки типов.

Ruby все равно будет проверять ваши типы во время выполнения. Вполне разумно оставить проверку типа интерпретатору и приложить усилия к функциональным тестам.

0 голосов
/ 26 мая 2011

Я пропущу первые два вопроса и отвечу на третий.Если единственным атрибутом CarServiceHistoryEntry является строка, то да, удалите CarHistory (а также CarServiceHistoryEntry) и добавьте атрибут Car_history в Car, который будет просто массивом строк.Пока не доказано обратное, чем проще, тем лучше.

Что касается утки, вы никогда не захотите проверить, является ли что-то «только», только посмотрите, отвечает ли оно (максимум).

Наконец, чтобы ответить на вопрос № 1,нет, это должно быть еще проще:)

Надеюсь, это поможет, Брайан

...