Ruby组成。为什么要使用Class,而不是Module?

时间:2017-08-30 17:08:39

标签: ruby composition

许多Ruby组合的例子都是这样的:

class GUI
  def get_input
    gets.chomp
  end
end

class Computer
  def initialize
    @ui = GUI.new
  end

  def get_input
     @ui.get_input
  end
end

但是,我认为这可能是

module GUI
  module_function

  def get_input
    gets.chomp
  end
end

class Computer
  def initialize
    @ui = GUI
  end

  def get_input
    @ui.get_input
  end
end

太。 那么为什么我们在这里使用Classes而不是模块?

1 个答案:

答案 0 :(得分:0)

这不是一个非常好的组合示例,因为GUI没有使用内部状态。如果你做了这样的事情,那将是一个更明确的构成案例:

class GUI
  def initialize(prompt)
    @prompt = prompt
  end
  def get_input
    puts @prompt
    gets.chomp
  end
end

class Computer
  def initialize
    @ui = GUI.new("enter text")
  end

  def get_input
     @ui.get_input
  end
end

使用此代码,每个计算机实例都有自己的GUI实例,具有自己的绑定行为(提示文本的值)。

这也可以通过模块完成,如下所示:

module GUI
  def get_input
    puts @prompt
    gets.chomp
  end
end

class Computer
  include GUI
  def initialize
    @prompt = "enter text"
  end
end

至于为什么类实现可能被认为比模块更好 - 嗯,有利有弊。使用该模块,计算机类可以更短,并且不需要定义get_input方法本身,因为它包含在mixin中。但是,从长远来看,类方法更明确,可能更易于维护。

至少有两个原因。首先,GUI明确定义了它的依赖关系。如果传递了错误的参数数量,Initialize将引发错误。但是如果未设置实例变量将为nil,因此如果在其他地方使用GUI,则可能会错过该详细信息。其次,定义像def get_input; @ui.get_input; end;这样的包装器方法似乎是多余的,但实际上有时可能很有用。如果您愿意,它可以让您Computer#get_inputGUI#get_input略有不同。

在此处回顾您的原始示例。就像我说的那样,它并没有很好地利用构图。由于GUI类没有依赖关系或内部状态,因此它可以是自包含的,也不需要实例化:

class GUI
  def self.get_input
    gets.chomp
  end
end

class Computer
  def get_input
    GUI.get_input
  end
end

请注意,您可以将class GUI更改为模块,它会产生相同的效果。您也可以使用module_method代替def self.,如下所述:https://idiosyncratic-ruby.com/8-self-improvement.html