1

我有一些像这样的课程:

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_fileand实现pick_first_word。我希望这由我发送到的文件类型来控制MyClass

问题

什么是更改initialize方法的好方法,MyClass以便它根据我发送的文件类型启动正确的类。我可以通过文件名上的 if/else 来做到这一点,但这似乎不太可扩展。

有没有比改变initialize方法更好的方法来做到这MyClass一点?

  def initialize (file_name)
    if (file_name == "word.txt")
      @word = Word.new(file_name)
    else
      @word = Movie.new(file_name)
  end

这种实现似乎不是很有可扩展性。

4

2 回答 2

0

It's all a matter of tradeoffs -- in this case, you want just enough complexity to handle a reasonable number of cases.

If there are only two options, I think that if statement looks just fine. A 'case' statement (aka a switch statement) can be DRYer, and you may want to explicitly say "movie.txt", e.g.

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

or extract a class_for_file_name method if you don't like putting a case statement in parens, even though it's pretty fun.

If your set of polymorphic classes gets bigger, you might get more mileage out of a lookup table:

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

And of course, maybe you're oversimplifying and you really want to switch on the file extension, not the file name, which you could get with File.extname(file_name).

You could also get even fancier and ask each concrete class whether it handles this file name; this feels more OO -- it puts the knowledge about foos inside the Foo class -- but is arguably more complicated:

class Word
  def self.good_for? file_name
    file_name == "word.txt"
  end
end

class Movie
  def self.good_for? file_name
    file_name == "movie.txt"
  end
end

...

def class_for_file_name file_name
  [Word, Movie].detect{|k| k.good_for? file_name}
end    

BTW this problem more or less fits the design pattern called Abstract Factory; you may want to look it up and see if any of its analyses inspire you.

于 2013-04-17T17:46:12.333 回答
-1

试试 FileMagic 库。

gem install ruby-filemagic

例子:

require 'filemagic'
type = FileMagic.new.file file_name
于 2013-04-17T17:24:03.617 回答