2009-09-11 45 views
9

作爲框架設計指南,它已被微軟給出,properties應該彼此獨立,不依賴於以任何特定順序設置。C#基礎知識製作屬性原子

假設您有一個需要支持昏暗度和麪積計算的三角形類。你會如何模型?

當然,這是被認爲是笨拙的,因爲區是依賴於基礎和被首先設置高度設計:

class Triangle{ 
    public double Base {get;set;} 
    public double Height {get;set;} 
    public double Area { 
     get{ 
      return (Base * Height)/2; 
     } 
    } 
} 

假設你使用構造函數,可以確保這種情況下默認,但就是這正確的做法?

class Triangle{ 
    public Triangle(double b, double h){ 
     Base = b; 
     Height = h; 
    } 

    public double Base {get;set;} 
    public double Height {get;set;} 
    public double Area { 
     get{ 
      return (Base * Height)/2; 
     } 
    } 
} 

您仍然有一個屬性依賴於其他屬性。爲了成爲一個純粹的,我可以看到只有幾個方法(我猜他們可以合併):

  1. 製作基地/身高都只能在構造函數中

  2. 製作設置只讀成員面積計算成一種方法。

  3. 使用某種工廠模式+只讀成員來確保雖然可能存在依賴關係,但值只能由實例化Triangle類的方法來設置。

問題:

  1. 是指引實用(你有沒有爲了支持了很多複雜的模型轉換成你的類)? [例如,一個SqlConnection類允許初始化連接字符串屬性,但可以讓你改變它的各個部分,如命令超時]

  2. 你如何管理讓你的特性相互獨立的?

  3. 對於使用Silverlight/MVVM類型體系結構的人來說,您是否因爲數據綁定適用於對象而接受屬性中的依賴項?例如,綁定顯示屏幕上高度,底部和區域的三角形實例。

回答

15

微軟真的試圖說「不要以任意順序調用屬性會導致意外行爲的方式設計你的類」。你的類的用戶不會期望請求一個值(使用一個屬性)來產生尷尬的副作用。

這屬於最不驚奇的原則。

我認爲這是一個完全實用的準則要遵循。屬性不應該有意想不到的副作用。

你提出了一個很好的問題:「你如何管理保持你的屬性相互獨立?」。很小心!我儘可能地消除狀態(並相應地減少屬性的數量)。另外,通過分解類來劃分狀態是另一種策略。這本身就是一個很好的問題......

就三角類而言,我認爲您在代碼中呈現的兩種解決方案都是有效的。如果它是由我決定的,我會設計三角形,使它不可變,並且在構造函數中考慮寬度和高度。

+0

好,簡明扼要。 – 2009-09-11 23:50:58

3

最簡單的方法是隻接受構造器的底和高值,然後暴露所有的人都爲只讀屬性:

class Triangle 
{ 
    private double base; 
    private double height; 

    private Triangle() { } 

    public Triangle(double base, double height) 
    { 
     this.base = base; 
     this.height = height; 
    } 

    public double Base 
    { 
     get 
     { 
     return this.base; 
     } 
    } 

    public double Height 
    { 
     get 
     { 
     return this.height; 
     } 
    } 

    public double Area 
    { 
     get 
     { 
     return (this.base * this.height)/2; 
     } 
    } 
} 
+1

爲什麼你會將它們暴露爲只讀?然後,你不能改變三角形......當然,如果你看到三角形是一個值類型(因此是不可變的),那麼你有一個觀點,但是在這個例子中有必要使三角形成爲值類型 ? ... 我認爲topicstarter剛剛誤解了指導原則。 :) – 2009-09-11 23:11:01

+1

總是讓對象不可變,除非你有一個令人信服的理由不要。三角形就是一個很好的例子 - 你爲什麼要改變它而不是創建一個新的?並不是可變對象最初是可怕的,但是將其中一個放入多線程場景中,除了「三角形」對象的程序員決定使用setter編程外,您突然之間需要進行同步,沒有什麼好的理由。 – 2009-09-11 23:43:38

+0

你不能使用base作爲變量名,它是一個關鍵字。它也不能是參數名稱和類變量名稱 – 2009-09-11 23:55:00

2

我想我會去爲它具有三角形類一個構造函數,其基地參數爲&高度,因爲三角形不能存在(imho)沒有基地或高度。

Offcourse,該地區屬性有一個依賴於基地&高度,但我沒有看到這方面的問題? 我認爲,如下的MS方針應該解釋:

性質應該是獨立的 彼此,而不是依賴於以任何特定的順序 集。

含義-imho-你不應該有一個約束,你首先必須設置基本屬性,並且只有當基本屬性已經設置,你可以設置高度屬性。
我認爲這就是上述指南的含義。

接下來,你的Area屬性是不可設置的,因此它沒有問題。 :)

0

一些屬性將固有地相關和依賴。重點是先設置底座,然後高度應該與設置高度相同,然後是底座。不設置其中之一,然後檢查該區域是沒有意義的。

0

選擇選項2.將Area設置爲方法並將其稱爲CalculateArea。應該使用屬性來封裝狀態而不是行爲。該區域可以從基地和高度計算並不意味着它本身應該是國家;相反,這是一個有力的論據,認爲區域應該不是是狀態。

class Triangle 
{ 
    public Triangle(double b, double h) 
    { 
     Base = b; 
     Height = h; 
    } 

    public double Base { get; set; } 
    public double Height { get; set; } 

    public double CalculateArea() 
    { 
     return (Base * Height)/2; 
    } 
} 

這讓消費者知道獲取三角形的區域需要真正的工作,而不是簡單地訪問狀態。