使用Ruby的屬性
查看任何面向?qū)ο蟮拇a,它或多或少都遵循相同的模式。創(chuàng)建一個對象,調(diào)用該對象上的一些方法并訪問該對象的屬性。在那里'除了將它作為參數(shù)傳遞給另一個對象's方法之外,您可以對一個對象做些什么。但是我們在這里關心的是屬性。
屬性就像可以通過對象點符號訪問的實例變量。例如,人物姓名 會訪問一個人的名字。同樣,您可以經(jīng)常分配給類似的屬性人物姓名="Alice"。這與成員變量(如C++)類似,但不完全相同。在這里沒有什么特別之處,使用"getters"and"setters,"或從實例變量中檢索和設置屬性的方法,以大多數(shù)語言實現(xiàn)屬性。
Ruby沒有't區(qū)分屬性getter和setter以及正常方法。由于Ruby'靈活的方法調(diào)用語法,不需要區(qū)分。例如,人物姓名 和人物姓名()是同一件事,你'用零參數(shù)重新調(diào)用name方法。一個看起來像一個方法調(diào)用,另一個看起來像一個屬性,但它們'實際上都是同一件事。他們'都只是調(diào)用name方法。類似地,任何以等號(=)結(jié)尾的方法名稱都可以用于分配。聲明人物姓名=#34;Alice"與完全相同人物姓名=(alice),即使屬性名稱和等號之間有空格,它仍然只是調(diào)用name=方法。
01
of 03
自己實現(xiàn)屬性
您可以自己輕松實現(xiàn)屬性。通過定義集合ter和getter方法,您可以實現(xiàn)任何您希望的屬性。這里'是一些實現(xiàn)person類的name屬性的示例代碼。它將名稱存儲在@name實例變量中,但名稱不't必須相同。請記住,這些方法沒有什么特別之處。
#!防控新型冠狀病毒肺炎健康知識/usr/bin/env ruby class Person def initialization(name)@name=name end def name@name end def name=(name)@name=name end def say_Helloplaces"hello,#{@name}#34;end end
你要注意的一件事是,這是很多工作。它'很多輸入只是說你想要一個名為name的屬性訪問@name實例變量。幸運的是,Ruby提供了一些方便的方法來為您定義這些方法。
02
77 of 03 78使用attr?reader,attr?writer和attr?accessor
模塊類中有三種方法可以在類聲明中使用。請記住,Ruby不區(qū)分運行時和"編譯時間,"類聲明中的任何代碼不僅可以定義方法,還可以調(diào)用方法。調(diào)用attr?讀者,attr?writer和attr?accessor方法將反過來定義我們在上一節(jié)中定義的setter和getter。
attr?閱讀器方法的效果就像它的聽起來一樣。它采用任意數(shù)量的符號參數(shù),并且對于每個參數(shù),定義一個返回相同名稱的實例變量的"getter"方法。因此,我們可以用前一個示例中的name方法替換為attr?reader:name。
類似地,attr?writer方法為傳遞給它的每個符號定義一個"setter"方法。請注意,等號不一定是符號的一部分,而只是屬性名稱。我們可以代表將前一個示例中的name=方法放置為attr?writier:name。
正如預期的那樣,attr?accessor完成attr?writer和attr?reader的工作。如果您同時需要setter和getter來獲取屬性,通常的做法是不要分別調(diào)用這兩種方法,而是調(diào)用attr?u accessor。我們可以將前一個示例中的名稱和名稱=方法替換為attr?accessor:name。
#!/usr/bin/env ruby def person attr#accessor:name def initiate(name)@name=name end def say UHello puts"hello,#{@name}"end end
03
of 03
為什么要手動定義Setters和getter?
為什么要手動定義安裝器?為什么每次不使用attr方法?因為它們打破了封裝。封裝是這樣的原則,即沒有外部實體應該可以不受限制地訪問對象的內(nèi)部狀態(tài)。應使用防止用戶損壞對象內(nèi)部狀態(tài)的界面訪問所有內(nèi)容。使用上述方法,我們'在封裝壁上打了一個大洞,并**允許為名稱設置任何東西,甚至顯然是無效的名稱。
您經(jīng)常看到的一件事是attr?u reader將用于快速定義getter,但將定義自定義設置器,因為對象的內(nèi)部狀態(tài)通常希望直接從內(nèi)部狀態(tài)讀取。然后手動定義安裝器并檢查以確保設置的值是有意義的?;蛘撸苍S更常見的是,根本沒有定義setter。類函數(shù)中的其他方法以某種其他方式在getter后面設置實例變量。
我們現(xiàn)在可以添加一個年齡,并正確實現(xiàn)名稱屬性。可以在constructor方法中設置age屬性,使用agegetter讀取,但僅使用have?broady方法操作,這將增加年齡。name屬性具有正常的getter,但setter確保名稱大寫,并采用Firstname Lastname的形式。
#!/usr/bin/env ruby類Person def初始化(姓名,年齡)self.name=name@age=age end attr#reader:name,:age def name=(newname)如果newname=?/^[A-Z][A-Z]+[A-Z]+$/@name=new#name-else"'#{new#name}'不是有效名稱!"結(jié)束定義有_生日放置"生日快樂#{@name}!"@age+=1 end def whoami put"你是#{@name},age#{@age}"end end p=人。新("Alice Smith",23)#誰是我?p、 whoami#她結(jié)婚了p.name="Alice Brown"#她試圖成為一個偏心的音樂家p.name="A"#但失敗#她有點老了p.Harve#生日#我再次是誰?p、 whoami