2010-07-07 58 views
26

我正在閱讀「清潔代碼」一書,並且正在與一個概念掙扎。在討論對象和數據結構時,它聲明以下內容:清潔代碼:對象是否具有公共屬性?

  • 對象將其數據隱藏在抽象背後並暴露對這些數據進行操作的函數。
  • 數據結構暴露他們的數據並且沒有有意義的功能。

所以,我從中得到的是,我不應該在我的對象上有任何公共屬性,我應該只有方法執行屬性的操作。如果我確實需要訪問屬性,他們應該在數據結構上,這可以從我的對象上的方法返回?採用這種方法,似乎我需要一個GetHeight()和SetHeight()方法來爲我的對象的Height屬性,而不僅僅是使用得到集合的屬性。

也許我並不完全瞭解正在建議的內容,但這是我對「對象的理解」。如果你能幫助我理解這一點,我將不勝感激!

在此先感謝!

+2

要添加到使用公用propertiers下面的答案,這種混淆可能源於許多語言不支持屬性的事實。在這種情況下,您可以在訪問方法和公共字段之間進行選擇,正確的選擇始終是訪問方法。 C#沒有這個問題,因爲它支持屬性。 – 2010-07-07 13:40:07

回答

17

公共財產很好。不必寫明確的GetHeight()SetHeight()方法是屬性的全部內容。 C#中的一個屬性是而不是數據;最好將其視爲一對吸氣/吸氣方法。 (屬性實際上編譯成生成的IL中的方法。)

數據隱藏是可能的,因爲您可以在不更改接口的情況下更改實現。例如,你可以改變

public int Height { get; set; } 

public int Height { get { return m_width; } set { m_width = value; } } 

,如果你決定,你的目標應該始終不散。使用你的類的代碼不需要任何修改。

所以如果你的對象暴露了公有屬性,它仍然「隱藏它的數據在抽象之後,並暴露了對這些數據進行操作的函數」,正如書中的建議。

4

屬性實際上是方法。
編譯器編譯屬性以獲取/設置MIL方法。

30

事實上,一個C#屬性不是數據,是一個訪問器,所以它是一個對數據進行操作的函數。

你應該避免公共領域,而不是公共財產。

+3

是的,但公用字段在數據傳輸對象上是可以的 – 2010-07-07 14:19:33

+2

我避免了DTO,但是在特定的情況下。當必須使用它們時,我更喜歡自動屬性。 – onof 2010-07-07 15:02:43

+0

對於幾乎所有的項目,沒有理由偏好屬性而不是字段,以及喜歡字段的幾個理由。字段爲:[1]保證行爲(改變屬性以添加行爲需要重新編譯,這是*好的*); [2]有時更快,永遠不會更慢; [3]代碼較短; [4]可以是'readonly',它比'get'只有更強的保證。如果您正在編寫一個公共API,其中的屬性需要允許在將來版本中的行爲與二進制兼容或需要私有setter(但考慮使用「readonly」),則只能使用屬性。 – 2013-01-24 12:19:24

2

使用私人字段生成公共訪問器會在用戶代碼和您的類之間建立一個契約。理想情況下,這個合同不應該修改代碼。

在C#中,執行合同合規的方式是使用interface。接口將允許您指定所需的方法和屬性實現,但不允許使用字段。另外,在.NET的各個不同點上,屬性通常比字段更受歡迎。例如PropertyGrid控制只枚舉的屬性,ASP.NET MVC模型類需要的屬性等

3

屬性基本上爲getter和setter方法手短。 Getter和Setter方法的意義在於讓對象處理對變量的任何操作,以便您可以執行任何額外操作(如數據驗證)而不會產生不必要的後果。

我認爲你可能會掛在自動屬性,它沒有後備變量,因此,看起來像變量本身。

0

其實通過使用屬性例如

public class Temp 
{ 
    public int SomeValue{get;set;} 
    public void SomeMethod() 
    { 
    ... some work 
    } 
} 

由於存在隱式變量來存儲值集並由SomeValue屬性返回,因此您正在隱藏其數據。

如果你有

public class Temp 
{ 
    private int someValue; 
    public int SomeValue 
    { 
    get{ return this.someValue;} 
    set{ this.someValue = value;} 
    } 
    public void SomeMethod() 
    { 
    this.someValue++; 
    } 
} 

然後你就會明白我的意思。您隱藏對象的數據someValue並使用SomeValue屬性限制對其的訪問。

3

這本書試圖描述的理論,一個對象不應該暴露如何實際實現類。在更復雜的對象中,許多內部變量並不一定從外部角度傳達正確的信息,而應該只有對它們採取行動的方法。

但是,當你擁有簡單的物體時,制定這條堅硬而快速的規則會分崩離析。在矩形的情況下,高度和寬度是用戶希望知道的基本屬性。而且由於這個實現很直接,所以不使用get和set會讓你的代碼比它需要的更復雜。

10

它主要是術語「財產」的另一個定義。 C#中的一個屬性並不是大多數其他語言所認爲的屬性。

實施例:
A C++公共屬性是:

class foo 
{ 
    public: 
    int x; 
}; 

C#中的相應的術語將是一個公共字段:

class foo 
{ 
    public int x; 
} 

我們在C#名稱類型作爲屬性將是制定者和其他語言的獲得者:

C#:

class foo 
{ 
    public int X { get; set; } 
} 

相應的C++:

class foo 
{ 
    private: 
    int x; 

    public: 
    void setX(int newX) { this->x = newX; } 
    int getX() { return this->x; } 
} 

簡而言之:
C#屬性是完全沒事,只是不要盲目默認他們得到集,不要使每一個數據字段在類中公共財產,想想你的班級的用戶真的需要知道/改變。

1

像這個線程中的其他帖子我會指出,在C#中的屬性只是你提到的訪問函數的特例。事實上,您可以在對象中的IL中修改get_Property和set_Property方法,該方法有一個標誌,指示它們是屬性,對於實現add_和remove_前綴方法的事件也是如此。

處理抽象的一個重要區別是設置屬性是否會對對象起作用,而不僅僅是更新內部狀態或拋出PropertyChanged異常。

如果您查看許多內部BCL對象,則可以按照您可以按任何順序設置所有屬性的方式來實現屬性,以配置對象。如果任何複雜的處理完成,那麼通常描述將要發生的方法是更好的選擇。

9

當您完成清潔守則,我建議你讀鮑勃·馬丁公司的另一本書:

Agile Principles Patterns and Practices In C#

在這本書的書廣大ammount的討論一個案例研究,並在其中, Bob應用Clean Code中討論的原則。我首先閱讀Clean Code,但回想起來我認爲應該先閱讀「敏捷模式」,因爲Clean Code更像是一本日常手冊或手冊中的優秀SW原則。

例如,在「敏捷模式......」下面的代碼被用於:

public class OrderData 
{ 
public string customerId; 
public int orderId; 
public OrderData() {} 

... 

} 

使用公共數據涉及您的問題的下列驗證:

別使用公衆 數據成員不會被冒犯。這不是 真正意義上的對象。它僅僅是一個用於數據的容器 。它沒有 有趣的行爲,需要封裝 。使數據變得私密,並且提供 獲取者和設置者將是浪費時間的 。我可以使用結構 而不是類,但我希望 OrderData通過引用 而不是按值傳遞。


旁白:

就個人而言,我不得不說,羅伯特·馬丁已經向SW開發者社區一個巨大的貢獻(與馬丁·福勒,邁克爾羽毛一起。)這些書。我認爲他們必須閱讀。

+0

還有[清潔編碼](http://www.amazon.com/The-Clean-Coder-Professional-Programmers/dp/0137081073) - 不同的主題,但很值得閱讀恕我直言。 – TrueWill 2013-07-04 15:00:39

2

這是交易。

雖然公共變量有時可能會有用,但通常最好讓它們保密。

如果對象是唯一一個控制其變量的對象,那麼保持代碼的組織很容易。

想象一下,你想保持0到200之間的高度。如果你有一個方法來設置你的身高,你可以很容易地監控這個。

例如(我將使用Java進行速度的緣故):

public void setHeight(int newHeight) 
{ 
    if (newHeight < 0) 
     height = 0; 
    else if (newHeight > 200) 
     height = 200; 
    else 
     height = newHeight 
} 

正如你所看到的,這種做法是很有條理和控制。

現在想象一下,我們有一行代碼在外部編輯這個高度,因爲您選擇公開它。除非您在代碼之外控制它,否則您可能會得到一個與您的程序不相符的高度。即使你沒有想要控制它,你會重複代碼。

非常基本的例子,但我認爲它得到了重點。

5

雖然公共屬性不是立即碼味,認爲這篇文章:

Coding with Reason by Yechiel Kimchi(從書97件事每個程序員都應該知道

」 ......不問對象讓信息與之合作,而是要求對象用已有的信息完成工作。「

這不會始終發揮作用(例如,數據傳輸對象)。我注意的是Inappropriate Intimacy

+2

+1爲報價掛在我的桌子上!感謝您的參考。 – JSprang 2010-07-07 18:02:17

+0

這是嚴格的OOP方法。在某些情況下很難實現。考慮MVVM模式。 – onof 2010-07-09 20:40:59

3

在純粹的面向對象中,「一個真實的對象」必須完全隱藏它用來履行責任的數據。因此,無論是通過公共領域,公共領域還是公共的getter/setter函數來完成,都必須避免暴露內部數據。

內部數據也沒有隱藏只是通過路由訪問它通過一個屬性被抽象!

要回答你的問題: - 避免公共屬性,如果你正在寫一個對象 - 如果你正在寫的數據結構(公共領域會做的工作,太)