2017-08-30 76 views
0

一个大量的红宝石组成的例子是这样的:红宝石组成。为什么使用Class而不是Module?

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 not Modules?

+5

https://stackoverflow.com/questions/151505/difference-between-a-class-and-a-module或https://lh4.googleusercontent。 com/e_Eml6aYg1udItOLjQCzUKF1L2K1JcjyZTnzYwcP7A = w1530-h800-no或http://www.vikingcodeschool.com/professional-development-with-ruby/classes-vs-modules可能有帮助,但基本上'Class'是一种特殊的'Module'可以实例化。一个'Class'是一个“Object”的有状态表示,其中'Module'更像是一个无状态的方法集合(通常用于可重用性和共享功能) – engineersmnky

+0

感谢@engineersmnky,所以在构图中我们使用其他的函数,我们应该使用'module_function'-ed'模块吗? – Todoroki

+0

稍微补充一下我原来的评论。考虑一下'GUI'是否要存储用户输入,例如'def get_input; @user_inputs << gets.chomp; end'如果这是一个'Module',用户输入的内容将在'GUI'的所有实现中共享,或者在所有'Computers'中共享。 (可能不是你想要的),但作为一个类,每个'Computer's'GUI'都会将输入单独存储在它自己的'GUI'实例中。 – engineersmnky

回答

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 

至于为何类实现可能被认为比模块一个更好的 - 嗯,有优点和缺点。使用该模块,Computer类可以更短,并且不需要定义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

+1

第二个例子在我看来令人厌恶,因为它在'GUI'实现和包含类之间创建了一个松散的绑定。我说的很宽松,因为显然'puts nil'的影响是有限的,如果没有设置@ @ prompt',但我不相信'Module'应该依赖于这个类的内部,包括它。我实际上会考虑将'get_input'定义为'def get_input(prompt = nil);提示时提示; gets.chomp;结束'因为这扩大了功能,如'def名称; @name = get_input(“你叫什么名字?”); end' – engineersmnky

+0

总的来说这很好,但我必须同意@engineersmnky,因为第二个例子很脏。设置一个实例变量另一件神奇的事情是封装不好。 – tadman

+0

感谢您的回答和评论。我完全忘记了在一个实例中存储状态的想法......我的不好。我也同意@engineersmnky在这里,但略有不同的观点:不是混合更类似于继承而不是组成?这就是我在问题中使用'module_function'的原因。 – Todoroki