JavaRush /Java Blog /Random-TW /獲取器/設定器。邪惡的。和時期
angelina
等級 5

獲取器/設定器。邪惡的。和時期

在 Random-TW 群組發布
文章作者:Egor Bugaenko 2014 年 9 月 19 日 | 發表於:Core Java 獲取器/設定器。 邪惡的。 和點 - 1這個古老的爭論是由 Allen Holub 在他的著名文章中發起的,早在 2003 年,為什麼 getter 和 setter 方法是邪惡的- getter/setter 是反模式嗎?我們應該避免它們,還是我們應該這樣做?物件導向程式設計中必然需要。我將在這次討論中添加我的兩分錢。以下文字的重點是:getter 和 setter 是不好的做法;使用它們的人沒有任何藉口。但再次強調,為了避免誤解,我並不是建議盡量避免使用 get/set。不。我是說你甚至沒有讓他們接近你的程式碼獲取器/設定器。 邪惡的。 和點 - 2您對此聲明有何看法?值得你關注嗎?您使用 get/set 模式已經 15 年了,您是一位受人尊敬的 Java 架構師嗎?而且連一個陌生人的胡言亂語都不想聽嗎?嗯...我理解你的感受。我也有同樣的感覺,直到我讀到 David West 的書《物件思維》——這是我讀過的關於物件導向程式設計的最好的書。所以,請。冷靜下來,試著理解我想要解釋的內容。 爭議主題 在物件導向的世界中,存在一些反對「訪問器」(getter 和 setter 的另一個名稱)的爭論。它們都是非常正確的論點。讓我們快速瀏覽一下它們。 詢問,不要告訴:艾倫·霍魯布(Allen Holub)說,“不要詢問完成工作所需的信息;‘詢問’擁有該信息的實體來為您完成工作。” 違反封裝原則:一個物件可以被其他物件拆開,因為它們可以透過 setter 將任何資料嵌入到該物件中。物件根本無法足夠安全地封裝自己的狀態,因為任何人都可以更改該狀態。 實作細節揭示:如果您可以從另一個物件取得一個對象,那麼我們就過度依賴第一個物件的實作細節。如果明天它發生變化(例如,結果類型),那麼我們將不得不更改程式碼。上述所有理由當然都有道理,但這忽略了最重要的一點。 基本誤解 大多數程式設計師認為物件是具有方法的資料結構。我引用Bozhidar Bozhanov的文章:Getters和Setters並不邪惡。但大多數為其創建 getter 和 setter 的物件只包含資料。這個誤會是一個巨大的誤會造成的!對象“不僅僅儲存資料”。物件不是附加方法的資料結構。「資料儲存」的概念來自於物件導向的程式設計和流程語言,尤其是 C 和 COBOL。我會再次重複:物件不僅僅是資料元素和操作它們的函數的集合。對像不是資料對象。然後怎樣呢? 球和狗 在真正的物件導向程式設計中,物件是有生命的存在,就像你和我一樣。它們是活的有機體,有自己的行為、屬性和生命週期。一個活的有機體可以有一個二傳手嗎?你可以給狗狗附上(「設定」)一個球嗎?別想了。但這正是下面這段程式碼的作用:
Dog dog = new Dog();
dog.setBall(new Ball());
那你覺得怎麼樣?你能把球從狗身上拿下來嗎?好吧,我們假設你可以。萬一她吃了它而你幫她做了手術。在這種情況下,是的,您將能夠從狗那裡獲得(“獲得”)球。這正是我要說的:
Dog dog = new Dog();
Ball ball = dog.getBall();
或者一個更荒謬的例子:
Dog dog = new Dog();
dog.setWeight("23kg");
你能想像現實生活中的情況嗎?聽起來你每天都在寫嗎?如果是,那麼您就是一名過程程式設計師。承認吧。David West 在他的書第 30 頁上是這樣說的: 將成功的程式開發人員轉變為成功的目標開發人員的第一步是腦白質切除術。您需要腦葉白質切除手術嗎?我確實需要它,並且是在閱讀 West 的《對象思維》一書時得到的。 客觀思考 開始像物件一樣思考,您將立即重命名這些方法。您可能會得到以下結果:
Dog dog = new Dog();
dog.take(new Ball());
Ball ball = dog.give();
現在,我們把狗當作一種真正的動物,它可以從我們手中奪走球,如果我們要求的話,它也可以把它還給我們。為了以防萬一,我注意到狗不能返回 NULL。狗狗就是不知道 NULL 是什麼!客觀思考(思考)立即從你的程式碼中刪除NULL 引用獲取器/設定器。 邪惡的。 還有點 - 3
一條叫旺達的魚 (1988) 查爾斯‧克萊頓 (Charles Crichton)
此外,客觀思考將導致物件的不變性,例如我們範例中的「狗的重量」。您可以將程式碼重寫為如下所示:
Dog dog = new Dog("23kg");
int weight = dog.weight();
狗是一種不可改變的生物體,不允許外界任何人改變它的重量、大小、名稱等。她可以根據要求“說出”她的體重或姓名。公開對物件的某些「內部」屬性的查詢的公共方法沒有任何問題。但這些方法不是“getters”,它們永遠不應該接收“get”前綴。我們無法“擺脫”狗。我們不知道她的名字。我們請她告訴我們她的名字。你看得到差別嗎?我們在這裡甚至不討論語義。我們將過程式程式設計方法與物件導向的程式設計方法區分開來。在過程編程中,我們處理資料、操作它、取得它、設定它,並在必要時刪除它。我們是掌控者,數據只是被動的組成部分。狗對我們來說毫無意義——它只是「包含數據」。她沒有自己的生活。我們可以自由地從中獲取(get)我們需要的一切,並將任何資料放入(設定)其中。這就是 C、COBOL、Pascal 和其他過程語言的工作原理(worked)。而在物件導向的世界中情況則完全相反。在這裡,我們將物體視為活的有機體,有自己的出生日期和死亡時刻,有自己的個性和習慣,如果你願意的話。我們可以要求狗給我們一個資料(例如它的重量),它可以將資訊傳回給我們。但永遠記住,狗是活躍的組成部分。她決定請求後會發生什麼事。這就是為什麼物件的方法以 set 或 get 開頭是絕對錯誤的。這甚至不像許多人認為的那樣違反封裝性。這是因為您要么像物件一樣思考,要么仍在使用 Java 語法編寫 COBOL。 附言。是的,您可能會問:“JavaBeans、JPA、JAXB 和許多其他依賴 get/set 的 Java API 怎麼樣?” Ruby 中可以更輕鬆地建立存取器的內建函數怎麼樣?好吧,我能告訴你什麼...你運氣不好。留在程式 COBOL 的原始世界中比理解和擁抱真實物件的奇妙世界要容易得多。 附註_ 我忘了說,是的,透過 setter 插入依賴項也是一種可怕的反模式。但下一篇文章將詳細介紹這一點! 來源文章
留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION