为DRY打破Ruby类

时间:2013-04-17 16:54:03

标签: ruby design-patterns

我有一些这样的课程:

class Word
  def initialize (file_name)
    load_file(file_name)
  end

  def pick_first_word(score)
    #get first word
  end

  private
  def load_file(file_name)
    #load the file
  end
end


class MyClass < SomeOther
  def initialize (file_name)
    @word = Word.new(file_name)
  end
  def pick
    @word.pick_first_word
  end
  #some other code
end

dosomething = MyClass.new("words.txt")
dosomethingelse = MyClass.new("movies.txt")

所以我有一个Word的类,它读入一个文件并选择第一个单词。就像我希望有另一个课程,比如Movies,它将拥有自己的load_filepick_first_word实现。我希望这由我发送到MyClass的文件类型控制。

问题

更改initializeMyClass方法的好方法是什么,以便根据我发送的文件类型启动正确的类。我可以通过文件名上的if / else来实现,但这似乎不是很容易扩展。

除了将initialize的{​​{1}}方法更改为此内容之外,还有更好的方法吗?

MyClass

此实现似乎不具有可扩展性。

2 个答案:

答案 0 :(得分:0)

这都是权衡问题 - 在这种情况下,您需要足够的复杂性来处理合理数量的案例。

如果只有两个选项,我认为if语句看起来很好。 'case' statement(也称为switch语句)可以是DRYer,您可能想明确说出“movie.txt”,例如

@word = (case file_name
  when "word.txt"
    Word
  when "movie.txt"
    Movie
  else
    raise "Unknown file name #{file_name}"
  end).new(file_name)

或提取class_for_file_name方法,如果你不喜欢在parens中添加一个case语句,即使它非常有趣。

如果您的多态类集变大,您可能会从查找表中获得更多的里程数:

class_for_file_name = {
    "word.txt" => Word, 
    "movie.txt" => Movie, 
    "sandwich.txt" => Sandwich,
}
@word = class_for_file_name[file_name].new(file_name)

当然,也许你过分简化,你真的想要打开文件扩展名,而不是文件 name ,你可以用{{1 }}

你甚至可以变得更加漂亮,并询问每个具体类是否处理这个文件名;这感觉更多OO - 它将关于foos的知识放在Foo类中 - 但可以说更复杂:

File.extname(file_name)

BTW这个问题或多或少符合名为Abstract Factory的设计模式;您可能想要查看它,看看它的任何分析是否能激发您的灵感。

答案 1 :(得分:-1)

尝试使用FileMagic库。

gem install ruby-filemagic

示例:

require 'filemagic'
type = FileMagic.new.file file_name