2011-09-07 60 views
0

我有一個數據庫表,其中包含一個ID列和一個Name列。我的任務是設計一個接受其中一個ID作爲參數Main()的程序。什麼是設計這個類層次結構的最佳方法?

粗體是編輯2

我需要使用,必須在數據庫中存在該ID,以對應於一些代碼運行。表中的每一行都對應着稍微不同的代碼,但是它們中的很多代碼都是共享的。我需要一個能夠儘量減少代碼重複的設計。

到目前爲止,我所開發的抽象基類有一個抽象的Int32字段ID來執行在數據庫中具有其相應ID的派生類。通過這種方式,我可以反思派生類來找到ID與Main()參數匹配的實例並實例化該類。然後,我只需調用Main()中的虛擬方法,該方法運行已定義的派生代碼最多。

public abstract class Base { 
    public abstract Int32 Id { get; }  
    public void Foo() { 
     // Do something 
    } 
} 

public class Derived { 
    public override Int32 Id { get { return 42; } } 
    public void Foo() { 
     // Do something more specific 
    } 
} 

有沒有人有任何更好的想法如何實現我想要的?我喜歡將ID保留在類定義中的想法,但如果它有意義,我願意改變它。

謝謝!

編輯:

一件事,我不喜歡,這是我必須反映在每個派生類型和實例化類型檢查ID。有沒有人有更好的想法如何做到這一點?

+0

這是功課? – Xint0

+0

不,它適用於新的自動化引擎。 –

+0

如果你從數據庫的id中查找名字,你會如何處理這個名字。這聽起來像你仰望,並通過ID鍵入代碼...爲什麼要查找名稱? – bryanmac

回答

2

不使用屬性來定義類的ID,而是使用自定義屬性。這樣,你不必實例化對象來檢查它的ID是什麼。

當程序運行時,它可以掃描程序集中所有具有該屬性標記的類,並找到具有匹配標識的類,實例化該類,然後運行它的Foo方法。如果您在每次應用程序運行中多次執行這種查找,則可以使用您的自定義屬性安裝所有類,然後將它們放入字典中,以便通過ID快速查找。

您的代碼可能是這個樣子:

[AttributeUsage(AttributeTargets.Class)] 
public class CommandAttribute { 
    public CommandAttribute(int id) { 
     ID = id; 
    } 

    public int ID { get; private set; } 
} 

public abstract class Command { 
    public abstract void Execute(); 
} 

[Command(2)] 
public class MyCommand : Command { 
    public override void Execute() { 
     //Do something useful 
    } 
} 

使用自定義屬性的另一個優點是,你必須明確地標記的一切,是對被實例化候選者,並通過ID來執行,而不是假設比從你的基地派生的任何東西都是候選人。如果你在類之間共享代碼,你可能想爲它們製作一個通用的基類,它們是從你的基類派生出來的,但不應該被自己實例化或執行。

我不明白的一件事是,如果要運行的類是由ID標識的,那麼「名稱」字段的要點是什麼?如果您可以決定每個ID的名稱,那麼您可以使用名稱字段作爲要執行的類的完全限定類型名稱,從而避免必須掃描程序集中的所有類型(或應用程序域,這取決於您的搜索範圍)。但是,該設置更容易出現拼寫錯誤。

+0

感謝您使用屬性的建議。我絕對忽略了這個想法!不幸的是,我無法更改數據庫中的結構和數據,並且名稱列中包含不清楚的數據。 –

+0

你知道是否有辦法強制派生類必須具有屬性? –

+0

本機不在C#中。您可以創建自己的後編譯步驟,分析輸出程序集,並在不滿足這些約束條件時產生錯誤,但我認爲在實踐中它可能不會成爲問題。此外,通過強制所有通過ID執行的候選對象的類可以用屬性標記,而不是依賴於從基礎「Command」類派生的所有類都可以這樣執行的假設(有些可能僅用作其他命令類的基類,並不打算由ID執行)。 – Nimrand

1

這聽起來像你需要實施工廠模式。

我會定義一個接口:

public interface IWidget 
{ 
    void Foo(); 
} 

然後基類:

public abstract class WidgetBase : IWidget 
{ 
    public void Foo() 
    { 
     this.Bar() 
    } 

    protected virtual void Bar() 
    { 
     // Base implementation 
    } 
} 

工廠:

public static WidgetFactory 
{ 
    public static IWidget Create(int id) 
    { 
     // Get class name from id, probably use the name in your database. 
     // Get Type from class name 
     // Get constructor for Type 
     // Create instance using constructor and return it. 
    } 
} 

派生類:

public class DerivedWidget : WidgetBase 
{ 
    protected override void Bar() 
    { 
     // call base implementation 
     base.Bar(); 
     // derived implementation 
    } 
} 

在你的主:

public void Main(int id) 
{ 
    var widget = WidgetBase.Create(id); 
    widget.Foo(); 
} 
+0

單一責任原則!爲什麼在WidgetBase中實現工廠? – Domenic

0

我喜歡@使用工廠這類任務的XINT0的想法,但我想我還是會有助於另一個答案。

實現您最初的設計是將ID傳遞給基類的構造如下一個更好的辦法:

public abstract class Base { 
    public Int32 Id { get; private set; } 
    protected Base(Int32 id) { 
      this.Id = id; 
    } 
    public void Foo() { 
     // Do something 
    } 
} 

public class Derived : Base { 
    public Derived : base(42) {} 
    public void Foo() { 
     // Do something more specific 
    } 
} 
相關問題