簡體   English   中英

公共數據成員與Getters,Setters

[英]Public Data members vs Getters, Setters

我目前在Qt等C ++中工作。 我正在使用具有私有數據成員和公共成員功能的類。 我為班級中可用的數據成員提供了公共獲取器和設置器。

現在我的問題是,如果我們在類中具有數據成員的getter和setter方法,那么將這些數據成員設置為私有的意義何在? 我同意在基類中擁有私有數據成員聽起來很合邏輯。 但是除此之外,對我來說,擁有私人成員以及其獲取者和設置者也是如此。

或者相反,我們可以將所有變量都公開,這樣就完全不需要getter和setter了嗎? 擁有這些是一種好習慣嗎? 我知道擁有私有成員可以確保數據抽象,但是擁有getter和setter實際上可以非常輕松地訪問那些變量。 歡迎對此提出任何建議。

都不行 您應該具有執行操作的方法。 如果這些事情之一恰好與一個特定的內部變量相對應,那很好,但是應該沒有什么能傳達給班級用戶的。

私有數據是私有的,因此您可以隨時替換實現(並且可以進行完全重建,但這是另一個問題)。 將精靈從瓶子中取出后,您將發現無法將其推回。

編輯:在評論后我對另一個答案。

我的意思是,您問的是錯誤的問題。 關於使用getter / setter或擁有公共成員,沒有最佳實踐。 對於您的特定對象,只有什么才是最好的,以及它如何對某些特定的現實世界事物(或游戲中的虛構事物)建模。

個人獲得者/設定者是兩個邪惡中的較小者。 因為一旦您開始制作吸氣劑/裝料器,人們就會停止對哪些數據應該可見和哪些數據不應該可視化地設計對象。 對於公眾成員而言,情況甚至更糟,因為這種趨勢已使所有內容公開化。

相反,請檢查對象的功能以及將其作為對象的含義。 然后創建為該對象提供自然接口的方法。 自然接口涉及使用getter和setter公開一些內部屬性,即使如此。 但是重要的是,您需要提前考慮一下,並出於設計合理的原因創建了吸氣劑/吸氣劑。

不,它根本不是同一件事。

通過不同的類接口方法,可以實現不同級別的保護/實現隱藏:


1.公開數據成員:

  • 提供對數據成員的讀取和寫入(如果不是const)訪問權限
  • 揭示數據對象實際上存在並且實際上是該類的成員的事實(允許人們創建指向該數據成員的指針到成員類型的指針)
  • 提供對數據成員的左值訪問(允許創建指向該成員的普通指針)


2.一種返回對一條數據(可能到私有數據成員)的引用的方法:

  • 提供對數據的讀取和寫入(如果不是const)訪問權限
  • 公開了數據對象實際上存在但不公開它實際上是此類的成員的事實(不允許人們創建指向數據的指針到成員類型的指針)
  • 提供對數據的左值訪問(允許創建指向它的普通指針)


3. Getter和/或Setter方法(可能訪問私有數據成員):

  • 提供對該屬性的讀取和/或寫入訪問權限
  • 不會暴露數據對象實際上存在的事實,更不用說物理上存在於此類中的事實(不允許人們創建指向該數據的成員類型的指針或與此相關的任何類型的指針)
  • 不提供對數據的左值訪問(不允許創建指向它的普通指針)

getter / setter方法甚至沒有公開該屬性是由物理對象實現的事實。 也就是說,在getter / setter對的后面可能沒有物理數據成員。

綜上所述,看到有人聲稱getter和setter對與公共數據成員相同是很奇怪的。 實際上,它們沒有共同之處。

當然,每種方法都有變化。 例如,getter方法可能會返回對數據的const引用,這會將它放在(2)和(3)之間。

如果每個數據項都有獲取器和設置器,則沒有必要將數據設為私有。 這就是為什么為每個數據項都具有吸氣劑和設置劑是一個壞主意的原因。 考慮一下std :: string類-它(可能)具有一個getter,size()函數,並且根本沒有二傳手。

還是考慮一個BankAccount對象-我們應該讓SetBalance()設置器更改當前余額嗎? 不,大多數銀行都不會感謝您實施這種方法。 相反,我們想要類似ApplyTransaction( Transaction & tx )

使用Getter和Setter,您可以將邏輯應用於私有成員的輸入/輸出,從而控制對數據的訪問(封裝給那些了解其OO術語的人)。

公共變量使您的類的數據向公眾開放,以進行不受控制和未經驗證的操縱,這幾乎總是不希望的。

您還必須長期考慮這些事情。 您可能現在沒有驗證(這就是為什么公共變量似乎是個好主意的原因),但是有可能在以后添加它們。 提前添加它們會離開框架,因此減少了重構的范圍,更不用說驗證不會以這種方式破壞相關代碼了。

但是請記住,這並不意味着每個私有變量都需要自己的getter / setter。 尼爾(Neil)在他的銀行業案例中提出了一個很好的觀點,即有時Getters / Setters毫無意義。

公開數據。 如果有一天(您不太可能需要)在“ getter”或“ setter”中需要邏輯,則可以將數據類型更改為重載operator=和/或operator T的代理類(其中T =無論您使用哪種類型重新使用)來實現必要的邏輯。

編輯:控制對數據的訪問構成封裝的想法基本上是錯誤的。 封裝是關於隱藏實現的細節(通常!), 而不是控制對數據的訪問。

封裝是對抽象的補充:抽象處理對象的外部可見行為,而封裝則處理隱藏該行為的實現細節。

使用getter或setter實際上會降低抽象級別並公開實現-它要求客戶端代碼意識到此特定類將邏輯上的“數據”實現為一對函數(getter和setter)。 使用如我上面提出的代理提供真正的封裝-除了一個不起眼的角落情況下,完全隱藏了一個事實,什么是邏輯上的一段數據通過對功能的實際執行。

當然,這需要保留在上下文中:對於某些類,“數據”根本不是一個很好的抽象。 一般來說,如果您可以提供更高級別的操作來代替數據,那是可取的。 盡管如此,對於某些類來說,最有用的抽象是讀取和寫入數據,在這種情況下,(抽象的)數據應像其他任何數據一樣可見。 獲取或設置值可能涉及比簡單的位復制更多的事實,這是應向用戶隱藏的實現細節。

如果您確定自己的邏輯很簡單,並且在讀取/寫入變量時無需執行任何其他操作,那么最好將數據公開。 在C ++情況下,我更喜歡使用struct而不是class來強調數據是公共的事實。

但是,通常在訪問數據成員時您需要做一些其他事情,或者想給自己自由,以便以后添加此邏輯。 在這種情況下,getter和setter是個好主意。 您的更改將對代碼的客戶透明。

一個簡單的附加功能示例-您可能希望在每次訪問變量時都記錄一個調試字符串。

除了封裝方面的考慮(這是足夠的理由)之外,在有getter / setter方法的情況下,只要設置/訪問變量,就很容易設置斷點。

使用公共字段而不是獲取和設置方法的原因包括:

  1. 沒有非法值。
  2. 客戶端應該對其進行編輯。
  3. 為了能夠寫諸如object.XY = Z之類的東西。
  4. 要堅決保證價值只是價值,並且沒有與之相關的副作用(將來也不會)。

根據您使用的軟件類型,這些可能都是真正的例外情況(如果您認為遇到過這種情況,則可能是錯誤的),或者它們可能始終存在。 真的要看

(摘自基於價值的編程的十個問題 。)

在嚴格的實踐基礎,我建議你通過使所有數據成員的私人的啟動, 使他們的getter和setter私人。 當您發現世界其他地方(即您的“(l)用戶社區”)的實際需求時,就可以公開適當的getter和/或setter或編寫適當控制的公共訪問器。

同樣(出於尼爾的利益),在調試期間,有時在讀取或寫入特定數據成員時,有一個方便的位置掛起調試打印和其他操作很有用。 使用getter和setter方法,這很容易。 對於公共數據成員,這是后路的巨大痛苦。

我一直認為,在大多數編程語言中,getter和setter都是故意冗長的,專門使您對使用它們感到三思-為什么調用者需要了解類的內部工作原理,這才是您的首要問題。 。

我認為,僅使用getter和setter來獲取和設置值是沒有用的。 使用這種方法,公共成員和私有成員之間沒有區別。 僅在需要以某種方式控制值或認為將來可能有用時才使用getter和setter方法(添加一些邏輯不會使您編輯其余代碼)。

作為參考,請閱讀C ++准則(C.131)

我建議您沒有公共數據成員(POD結構除外)。 我也不建議您為所有數據成員都使用getter和setter方法。 而是為您的班級定義一個干凈的公共接口。 這可能包括獲取和/或設置屬性值的方法,並且那些屬性可以實現為成員變量。 但是,請勿為您的所有成員做吸氣劑和裝夾劑。

這個想法是您將界面與實現分開,從而允許您修改實現,而類的用戶不必更改其代碼。 如果通過getter和setter公開所有內容,則在使用公共數據方面沒有任何改善。

使用getter和setter方法將允許您修改將值​​提供給用戶的方式。

考慮以下:

double premium;
double tax;

然后,您可以使用此premium價值在各處編寫代碼以獲得溢價:

double myPremium = class.premium;

您的規格剛剛更改,從用戶的角度來看, premium + tax必須是premium + tax

您將必須在代碼中使用該premium所有地方進行修改,並對其加tax

如果相反,您是這樣實現的:

double premium;
double tax;

double GetPremium(){return premium;};

您所有的代碼都將使用GetPremium()並且您的tax更改將為一行:

double premium;
double tax;

double GetPremium(){return premium + tax;};

Getter和Setter主要存在,以便我們可以控制如何獲取成員以及如何設置成員。 Getter和Setter並不僅僅作為一種訪問特定成員的方式而存在,而是要確保在嘗試設置成員之前,它可能滿足某些條件,或者如果我們獲取它,我們可以控制我們返回該成員的副本。非基本類型的成員。 總的來說,當您想要流水化如何與數據成員進行交互時,應該嘗試使用g / s'ers,而沒有它們將導致該成員以特定方式使用。

返回值還會影響getter和setter的使用。 獲取變量的值或訪問私有數據成員變量是不同的。 按值保持完整性,按引用或按指針的程度不高。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM