2009-04-09 69 views
6

我正在C#2.0中工作,但這將適用於大多數面向對象的語言。當我創建包含私有字段的公共屬性的類時,我會在內部使用屬性或字段之間切換回&。當然,C#3.0使得自動屬性更容易,但它仍然可以應用。OO設計 - 您是否內部使用公共財產或私人領域?

重要嗎?

public class Person 
{ 
    private string _name = ""; 

    public string Name 
    { 
     get { return _name; } 
     set { _name = value; } 
    } 

    public Person(string name) 
    { 
     _name = name; //should I use the property or field here? 
    } 
} 

回答

2

主要是它就像一個代碼偏好​​,但我更喜歡使用公共屬性或曾經私有財產,你可以簡單地一些邏輯添加到屬性,而不按呼叫代碼進行任何更改。同樣在3.5 .NET中,你有有用的代碼糖作爲autoproperty。

2

我會建議使用屬性,你永遠不知道什麼時候會被做你的財產,即內在的東西。延遲加載,轉換,格式化,計算等,如果你使用的私有成員,這將帶來一個bug ......

0

通常我使用有一些例外的公共屬性,我可能希望避免寫入任何額外的代碼財產訪問者。有了C#3.0中的自動屬性,我很少手動創建後臺字段;通常只有當自動支持字段的默認值不適合我的財產時。

0

至少在Java中,有沒有辦法,你會使用公共字段,因爲美好的舊JavaBean規範,每個人都似乎使用。 我猜C#有屬性作爲第一語言結構。我會去那

+1

是的,它是C#的一大好處。 – Randolpho 2009-04-09 15:41:37

+0

對於我們這些不知道這些javabeaner事情的人來說,什麼是雅談話? – 2009-04-09 15:43:43

0

你應該使用「名稱」(屬性),因爲如果你想對這個值進行一些檢查,你可以把它放在「Name」屬性的setter中,然後將用於構造函數和最近設定值也是如此。

1

使用該屬性。或者更好的是,如果你使用C#3.0或以上版本使用自動屬性,像這樣:

public class Person 
{ 
    public string Name { get; set; } 

    public Person(string name) 
    { 
     Name = name; //should I use the property or field here? 
    } 
} 

如果使用屬性現在您就可以在修改代碼以使用自動屬性。

14

基本上,因爲你可以實現在屬性的驗證和其他邏輯,你應該通過財產,除非你有特殊原因無法訪問。

它有助於你的對象內的一致性,因爲你知道的方式,你的私有字段的值已經通過你選擇的任何苛刻要求把你的訪問或setter方法了。

在另一方面,構造都不可能是一個例外,因爲你可能需要設置的初始值。

但總的來說,我會說通過財產訪問。

編輯

A(瑣細/做作)例如

public class Person 
{ 
    private string _name = ""; 
    private List<String> oldnames = new ArrayList(); 

    public string Name 
    { 
     get { return _name; } 
     set 
     { 
      oldnames.Add(_name); 
      _name = value; 
     } 
    } 

    public Person(string name) 
    { 
     _name = name; //should I use the property or field here? 
    } 
} 

因此,在這種情況下,你會想構造跳過財產,但如果你再次使用該字段,你會由於您正在跳過「名稱歸檔」,導致代碼中出現錯誤。在您的財產中進行驗證的原因是,您不需要在訪問該字段的每個地方複製驗證代碼,因此即使使用私有方法,也不應該跳過驗證代碼。

0

這取決於。有時候,你會寫一些getters/setter來爲與該領域的任何現實交互做重要的預處理。例如,如果字符串字段的約束條件必須始終爲小寫,那麼至少有一個getter/setter方法必須調用.ToLower()或.ToLowerInvariant(),並且在您的類代碼中,您可能想要使用它來確保強制執行。

但是,也有時候您需要繞過預處理邏輯。事實上,我曾經看到過有些時候,開發人員無意中通過使用公共屬性而不是私人領域來創建無限循環(無法想象我的頭頂上的例子,對不起)。

Linq對於SQL生成的類是一個很好的例子,我認爲,因爲它們顯示了一個Property中可以存在多少邏輯。嘗試編寫一些擴展方法,您將開始瞭解其中的差異。

我認爲底線是它取決於你在類中的任何給定點使用什麼樣的邏輯,以及getters/setters中存在什麼樣的預處理。如果您不確定或者看起來無所謂,最好使用getters/setters/public Property,以便編寫更多可維護的代碼,這些代碼將遵循稍後添加的約束條件。

1

可能會出現您必須在內部訪問該字段的情況。例如,當您僅公開提供對屬性的只讀訪問權限,並且在實例化對象後,不允許更改該值。

public class MyClass 
{ 
    private string _MyProperty; 

    public MyProperty { get { return _MyProperty; } } 

    public MyClass() 
    { 
     _MyProperty = SomeVeryComplexPropertyInitializationLogic(); 
    } 
} 
1

如果使用字段名稱,則不會得到封裝。封裝不僅適用於類之間,而且適用於類。

如果在將來的某個點重新定義字段,但保留accessor/setter函數的簽名相同,不僅外部類使用您的類不會中斷,而且您自己的類中的內部例程也不會中斷。

就拿這段代碼中,鬆散的基礎上的代碼,在Apache Wicket框架顯示出來(雖然框架不會受到這個問題,我只是用它說明):

比方說,這是原班:

class RadioChoice { 
    private String prefix; 

    RadioChoice(String prefix) { 
    this.prefix = prefix ; 

    setPrefix(String prefix) { 
    this.prefix = prefix ; 
    } 
} 

在這裏,我們已經可以看到一個問題:同樣的操作this.prefix = prefix在拖地發生。它意味着要做同樣的事情,但是因爲它發生在兩個地方,所以「同一個事物」可以分成兩個不同的事物。 (將此與數據庫規範化相比較,這是一種專門用於防止這種情況的實踐。)

現在,Apache Wicket具有記錄如何呈現網頁的更改的概念,以便可以撤消這些更改。它通過存儲一個「撤消」對象列表來完成。一個RadioChoice的前綴是可以撤銷的事情之一,所以「前綴」二傳手必須記錄的變化:

class RadioChoice { 
    private String prefix; 

    RadioChoice(String prefix) { 
    this.prefix = prefix ; 

    setPrefix(String prefix) { 
    // save the old prefix 
    this.getPage().addChange(new PrefixChange(this.prefix)); 
    // set the new one 
    this.prefix = prefix ; 
    } 
} 

現在看看會發生什麼:因爲構造前綴直接設置,沒有變化被保存ctor。如果我們使用了setter,那麼ctor會在重構後自動「做正確的事情」。相反,我們必須重構設置器 ctor。

當然,我們的代碼仍然不是最佳少,在現實中,它應該是這樣的:

setPrefix(String prefix) { 
    // save the old prefix 
    this.getPage().addChange(new PrefixChange(this.getPrefix())); 
    // set the new one 
    this.prefix = prefix ; 
    } 
} 

斯科特邁爾斯有一系列關於此文章,他主張(在C++中,其具有自由函數)一類暴露原始函數(原始功能:函數不可能除了由類iteslf),並且所有可能被由出的基本功能的功能得以自由功能。這使得界面更精簡,界面更穩定。

在這同樣,到可以處理的類作爲只取決於它的原始接口之前,有更多的靈活性功能的程度;特別是,這些職能可能會被移出課堂。更一般地說,使用setter和getter將你從變化中隔離出來。