2012-04-11 60 views
5

可能重複:
C# - Is there a better alternative than this to ‘switch on type’?的最佳方式基於類型

考慮經典:

class Widget { } 
class RedWidget : Widget { } 
class BlueWidget : Widget { } 

在大多數情況下,在我的UI,我可以對待所有Widget一樣。但是,有一些細微的差異,我需要通過ifswitch

可能的方法:

枚舉指標 - 通過構造方法設置

enum WidgetVariety { Red, Blue } 

class Widget { 
    public WidgetVariety Variety { get; protected set; } 
} 

class RedWidget : Widget { 
    public RedWidget() { 
     Variety = Red; 
    } 
} 

// Likewise for BlueWidget... 

switch (mywidget.Variety) { 
case WidgetVariety.Red: 
    // Red specific GUI stuff 

case WidgetVariety.Blue: 
    // Blue specific GUI stuff 
} 

使用is

Widget w = ...; 
if (w is RedWidget) { 
    (RedWidget)w ... 
} 
else if (w is BlueWidget) { 
    (BlueWidget)w ... 
} 

我已經使出了這樣做的原因是1)大多數代碼已經有點用這種方式編寫了,但更加醜陋。 2)90%的代碼是相同的 - 基本上只需要根據類型對GridView中的一列進行不同的處理。

你會推薦哪個? (或任何人有更好的解決辦法嗎?)


編輯我知道我可能會建議訪問者模式,但只是看起來複雜,在這種情況下稀疏的,微小的差異。

編輯2 所以我有一個特殊的區別是我很難整理出這兩個類型不同的列。在一種情況下,它檢索一個bool值,並將其分配給網格單元格。在另一種情況下,它會得到一個字符串值。

我在這種情況下想,這應該是顯而易見的,我可以定義:

public object virtual GetColumn4Data(); 

public override GetColumn4Data() { return m_boolval; } 

public override GetColumn4Data() { return m_mystring; } 

這起初我覺得不對勁,由於使用的object。但是,我分配給單元格的屬性的類型,所以當然是這很有道理!

今天在辦公室時間太長了......

+3

聽起來好像你說的是:由於大部分代碼已經寫得很差,你需要通過編寫更難看的難以維護的代碼來延續這一趨勢。 – 2012-04-11 22:49:47

+0

如果你的子類有一個不同的類型,那麼也許基類應該是通用的。然後它變成'public virtual T GetColumn4Data(); ... public override bool GetColumn4Data(){return m_boolval; } ... public override string GetColumn4Data(){return m_mystring; }' – 2012-04-11 23:30:43

+0

@Sahuagin - 請保存更大的代碼片段以獲取答案。評論不公平。 – 2012-04-11 23:57:31

回答

9

還有另一種可能性。使用虛擬調度:

class Widget 
{ 
    public virtual void GuiStuff() { } 
} 
class RedWidget : Widget 
{ 
    public override void GuiStuff() 
    { 
     //... red-specific GUI stuff 
     base.GuiStuff(); 
    } 
} 
class BlueWidget : Widget 
{ 
    public override void GuiStuff() 
    { 
     //... blue-specific GUI stuff 
     base.GuiStuff(); 
    } 
} 
+0

當然....看我的編輯2 :-) – 2012-04-11 22:57:46

5

Subtype polymorphism是最好的解決辦法,以避免這種檢查是OO創建的主要原因之一。

Widget可能有一個方法DoSomething()(可能是抽象的),然後RedWidgetBlueWidget會覆蓋它。

另見Martin Fowler的Replace Conditional with Polymorphism

看:你有一個條件是選擇依賴於對象的類型不同的行爲。

重構:將條件的每一段移動到子類中的重寫方法。使原始方法抽象化。

+2

我不同意[這種]多態性是「OO爲什麼被創造」的觀點;它更像是一些「OO語言」的*效果。但是,其他位的+1。 (有更多的多態性比無聊 - 而且是危險的 - 例如在C#/ Java中發現的單派遣子類型。) – 2012-04-11 23:05:39

+0

@pst我看到你的觀點,有趣的話題 – jorgehmv 2012-04-11 23:25:01

0

對於編輯#2下的問題,您可以使用泛型類來使類型在不同的子類中有所不同,儘管它可能會或可能不適用於您,具體取決於您的設計。這可能會導致其他艱難的設計決策。

粗糙例如:

internal abstract class BaseClass 
{ 
    protected object mValue; // could also be defined as a T in BaseClass<T> 

    public object GetColumn4Data { get { return mValue; } } 
} 

// this is a group of classes with varying type 
internal abstract class BaseClass<T> : BaseClass 
{ 
    public T GetTypedColumn4Data 
    { 
     get { return (T)mValue; } 
     set { mValue = value; } 
    } 
} 

// these are not really necessary if you don't plan to extend them further 
// in that case, you would mark BaseClass<T> sealed instead of abstract 
internal sealed class BoolSubClass : BaseClass<bool> 
{ 
    // no override necessary so far 
} 

internal sealed class StringSubClass : BaseClass<string> 
{ 
    // no override necessary so far 
} 

但請注意,你不能真正得到這將對某些屬性或方法的不同返回類型的單一引用類型。參考文獻最多隻能返回一般類型(如object)。

+0

不幸的是,這裏不行。這種特殊的差異只是幾個小但重要的差異之一。如果它是唯一的區別,我會同意這種方法。 – 2012-04-12 00:58:26