1

我创建了一个程序来跟踪汽车里程和服务历史,以便更新用户对汽车的未来服务需求。

我有三个类:CarCarHistoryCarServiceHistoryEntry。第三个是直截了当的;它包含与服务相关的所有属性:日期、里程、执行的服务等。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可以添加a?我不能只通过 aString而不是设置然后添加CarServiceHistoryEntry我的单元测试吗?
  3. 由于 a 的唯一必要属性CarHistoryentries数组和to_s方法,我是否应该将这个类全部废弃并将其放入car类中?
4

3 回答 3

1

很难评论CarHistory班级与其他人的关系,但我相信随着你的进步,你会变得清楚。

您的一些方法可以简化,尽管我必须说我不明白ifin initialize,也许它只是倒退了,应该是> 0

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

def to_s
  @entries.join "\n"
end

是的,Ruby 应该很简单。您无需在代码中乱扔运行时类型检查。如果代码运行您的单元测试,那么您可以宣布胜利。无论如何,无数的显式转换往往会修补类型错误。

无论如何,Ruby 都会在运行时检查您的类型。将类型检查留给解释器并将您的精力投入到功能测试中是完全合理的。

于 2011-05-26T04:35:15.077 回答
1

对于 1 和 2,当您转向像 Ruby 这样的松散类型语言时,您需要释放对“严格类型”的紧握。

  • 你应该检查你的输入参数吗?传统的答案是肯定的。另一种方法是使用良好的名称和单元测试来记录并指定类型应该如何工作。如果它适用于其他类型,很好..这是一个额外的好处。因此,如果您传入一个不兼容的类型,它会因异常而崩溃,这在大多数情况下已经足够了。试一试,看看感觉如何(可能的结果:解放/“撤退!”。但给它一个公平的尝试。)。例外情况是,如果您正在为共享库设计公共 API - 其中规则不同。对于错误的输入,您需要快速且信息丰富地失败。
  • 至于将 car_history 加入汽车 - 我会问您的 Car 课程的职责是什么。如果保持自己的历史是其中之一,您可以将它们加入俱乐部。以后,如果你发现有很多与汽车历史相关的方法,你可以再次撤销这个决定,再次提取 CarHistory 类型。使用 SingleResponsibilityPrinciple 做出明智的决定。这只是 OOP - 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"
于 2011-05-26T04:37:35.860 回答
0

我将跳过前两个问题并回答第三个问题。如果 CarServiceHistoryEntry 的唯一属性是字符串,那么是的,废弃 CarHistory(以及 CarServiceHistoryEntry)并向 Car 添加一个 service_history 属性,它只是一个字符串数组。除非另有证明,否则越简单越好。

至于鸭子打字,您永远不会想测试某物是否“是”,只看它是否“响应”(最多)。

最后,回答问题#1,不应该更简单:)

希望这会有所帮助,布赖恩

于 2011-05-26T04:39:33.587 回答