2011-06-01 20 views
8

我有一個名爲DatabaseRow的抽象類,它在派生和構建後主要從Load(object id)方法加載。方法鏈接的最佳實踐(「return this」)

我有很多代碼創建類的新實例,從一個ID加載它,然後返回類。我想簡化這段代碼到一行代碼中(只是爲了整潔,有很多類只會有返回這些Loaded實例的屬性列表)。

我可以想到做這件事有兩種方式,但對我來說都不是「正確」的。

我在Load方法到底能return this;和使用return new Derived().Load(id);

2.我可以創建一個通用的方法返回一個載入的方法。

public static T LoadRow<T>(object id) where T : DatabaseRow, new() 
{ 
    T row = new T(); 
    row.Load(id); 
    return row; 
} 

我已經看到了使用相同的方法,數一些其他的代碼,但我從來沒有見過任何有經驗的開發人員推薦它,我也沒有穿過在.NET框架的任何方法來了做同樣的事情,所以也許這不是最佳做法?

有沒有人知道任何其他解決方案可能比這兩個更好?

解決方案:

閱讀SirViver的回答和評論後,我意識到,返回需要的所有屬性進行反正緩存。解決方案很不同,但類似於選項(我不希望任何人拿出這個答案,因爲我沒有解釋這部分設計)

所有這些實例將從從數據庫中的另一列中檢索的值(如果您喜歡,則使用數據庫關係)。我沒有試圖從這個值中加載新的實例,而是創建了一個方法來從列名稱加載實例並將加載的值緩存在Dictionary中。這很有效,因爲這是DatabaseRow類的主要功能之一。

private Dictionary<string, DatabaseRow> linkedRows; 

    protected T GetLinkedRow<T>(string key) where T : DatabaseRow, new() 
    { 
     if (linkedRows.ContainsKey(key)) return (T)linkedRows[key]; 
     else 
     { 
      T row = new T(); 
      row.Load(this[key]); 
      linkedRows.Add(key, row); 
      return row; 
     } 
    } 

回答

3

就個人而言,我認爲這是不好的做法,即對對象實例實際sideffects鏈的方法調用。說實話,我認爲這兩個例子都是非常醜陋的「黑客」,其唯一目的是保存兩行代碼。我不認爲結果實際上更具可讀性。

如果你想要一個記錄被立即加載,我可能會更願意提供一個構造函數變體,它會從你加載的ID開始,並使對象在構造時自動填充,儘管當我考慮它時,我會一點都不誠實 - 在單行中填充更多的信息並不能提供更多可讀取和可維護的代碼。

+0

在我的情況下,我有一個類繼承'DatabaseRow',並有5個屬性都使用這個相同的功能。有5行代碼,類似於'public Derived MyProperty {get {return new Derived()。Load(myInt); }}比將屬性分隔成多行代碼要容易得多。 – Connell 2011-06-01 12:01:17

+0

但是,財產法的「整潔」究竟如何呢?無論如何,在大多數情況下,屬性代碼應該由Visual Studio摺疊,並且不像你總是要經常看類實現。也就是說,構建和加載屬性訪問數據似乎非常危險。如果有人不知道結果需要緩存,可能會導致性能下降和/或意外行爲。 – SirViver 2011-06-01 12:13:34

+0

就是這樣!我現在覺得自己像個白癡。你對緩存的評論提醒我,我已經在我的DatabaseRow類的底部創建了這個函數! 'protected T GetLinkedRow (string key)其中T:DatabaseRow,new()'加載行並將其緩存在基於key的值的字典中。 – Connell 2011-06-01 12:20:16

2

1號在某些圈子中越來越受歡迎;它通常被稱爲流利編程當有一個接口定義了大量的這些方法並且可以組裝長鏈。成功完成此操作的關鍵是永遠不要定義有時返回this的方法,但其他時間將返回null。如果總是返回this(除非有例外),這是非常好的風格。

就我個人而言,我不喜歡像2號這樣的解決方案,因爲它可以說是違反了「一個責任」原則。

0

儘管我個人喜歡返回this的方法,因爲它允許它們被鏈接在一起,我認爲在.NET框架中(直到Linq),這是被折磨的。需要注意的原因是這樣的:

方法可以返回結果或更改對象的狀態。返回this有兩點:更改對象的狀態,然後返回「結果」 - 除了結果是修改的原始對象。這不符合用戶的期望。

關於什麼:

public class Derived : DatabaseRow 
{ 
    public Derived(object id): 
    { 
     Load(id); 
    } 
} 

而且使用這樣的:

return new Derived(id); 
+0

我完全同意你的第二段。我實際上最初使用的是類似於你的解決方案,但是我決定反對它,並改爲Load方法,因爲我不認爲構造函數應該有那麼多的功能(在這種情況下,執行SQL查詢) – Connell 2011-06-01 11:55:10

+0

@Connell Watkins:我有對於構造函數在我之前也有類似的想法,但現在往往認爲它們是對象處於可用狀態的保證。所以,如果這些對象只是在調用Load方法之後才被使用,那麼你真的可以把它放在構造函數中! – 2011-06-01 14:21:36

1

選項1只有在有可能沒有被加載的情況下才有可能被接受。這是由於該模式允許你這樣做:

return new Derived(); 

我個人更喜歡靜態方法。但我懷疑這只是個人喜好的問題。

由於ssg說另一個選項(讓我們稱它爲選項3)是重載Derived中的構造函數,它也可以工作,但是由於調用代碼中沒有任何內容到底是怎麼回事。

選項1:

return new Derived().Load(10); 

選項2:

return Derived.Load(10); 

方案3:

return new Derived(10); 

選項1看起來像你正在創建一個多餘的對象。選項2很好,因爲它看起來像是在做什麼。備選方案3令人困惑。

+0

這是完全有可能有一個類,而不是加載它。如果你在數據庫中創建一個新行,你需要創建一個新的實例,填充這些屬性,然後調用一個'Save()'方法。你是指通用的靜態方法嗎?或者每個派生類中的靜態方法? – Connell 2011-06-01 12:05:52

+0

啊,我剛剛看到你的編輯。選項2看起來很完美,但事情是這樣的,它需要我爲這種類型的每個派生類創建相同的靜態方法,這似乎是不必要的。 – Connell 2011-06-01 12:07:33