2017-08-30 34 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