2008-11-20 19 views
8

行,所以我在尋找一個一些代碼,看起來大致是這樣的:尋找一種設計模式,以取代huuuge如果對象類型

void DoSomething(object o) 
{ 
    if (o is Sometype1) { 
    //cast o to Sometype and do something to it 
    } 
    else if (o is Sometype2) { 
    //cast o to Sometype2 and do something to it 
    } 
    ... 
    else if (o is SometypeN) { 
    //cast o to SometypeN and do something to it 
    } 
} 

現在,一個辦法是讓所有的物品o是作爲參數,可以實現一個接口一樣

interface ICanHaveSomethingDoneToMe 
{ 
    //expose various properties that the DoSomething method wants to access 
} 

但這樣做的問題是,我不希望我的所有對象實現這個接口 - 在做一些方法並沒有真正與他們所屬的邏輯。我應該用什麼模式來處理這個問題?

我懷疑類似的

interface IPropertiesForDoingSomethingTo<T> 
{ 
    //expose various properties that the DoSomething method wants to access 
} 

一系列的實現可能會更好。我想爲每個對象類型實現一個實現,但我有這個新問題。我會在這點上需要有一個方法,如

IPropertiesForDoingSomethingTo<T> GetPropsGeneric(T t); 

但這是需要有一個大規模的開關呢?我應該定義與方法負載一類像

IPropertiesForDoingSomethingTo<Someobject1> GetProps(Someobject1 t); 
... 
IPropertiesForDoingSomethingTo<Someobject1> GetProps(SomeobjectN t); 

這相比於普通版本,您將無法在運行時添加新類型的問題。有沒有什麼狡猾的人可以用GetPropsGeneric中的DI容器來解決容器問題?謝謝!

回答

6

任何時候當你看到一個switch語句(或一系列if語句)正在檢查一個對象的類型時,這是缺少基類或接口的大紅旗。換句話說,代碼應該依賴於多態性,而不是測試對象類型如果你不能改變基類或實現一個接口,你可能會留下一個字典來模擬動態分配,而不是測試對象類型

。在C#中,您可以使用匿名代理作爲屬性訪問的方法,其中包括投影

至於屬性訪問,如果屬性不符合並且通過反射訪問不是一個選項,則可能需要提取屬性值上面的方法/委託並將它們傳遞給一個通用函數,而不是

+1

你可以在任何你不能改變的類上實現一個包裝,並讓它實現你的接口。然後只處理已包裝的對象。例如,我使用DataContext執行此操作,以便於進行單元測試。 – tvanfosson 2008-11-20 18:00:30

2

看起來你可能正在使用C#。我相信你可以創建附加到已經建立的類的「擴展方法」。

另一種方法是爲每種類型創建處理程序委託並將對委託的引用存儲在按對象類型鍵入的散列表中。

然後,您的「DoSomething」方法可以通過傳入並執行的對象的類型來查找合適的委託。

0

一個真實的例子會更有幫助。如果您只是簡單地改變相關類的一個方法的實現,那麼就像@Steven A. Lowe說的那樣,您最好使用多態併爲此使用子類關係。如果班級不參與「是一種」關係,那麼Visitor等其他模式可能會更合適。

0

多態性是基礎對象被傳入的答案,但它的樣板和語義複雜性要比你想要的要多得多。

這將需要你的功能分流到派生類和一個「虛擬」功能來實施。

0

我認爲這更多的是面向方面編程方法的問題。

我想讓你的DoSomething方法以ICanHaveSomethingDone接口爲參數。然後,我將定義ICanHaveSomethinhgDone接口,並從中爲它實現DoSomethingToMe的每個實現類別派生不同的sublcasses(您希望DoSomething的每個對象一個)。他們每個人都只需要一個你想要做的類型的構造函數,所以當你去調用DoSomething時,你實際上會調用一個Factory(非常簡單,只是從輸入類型創建一個ICanHaveSomethingDone類的實例,創建一個實現DoSomethingToMe方法的類的實例,並且該實例具有適當的底層對象代碼。

本質上,可以這樣想;您正在定義一個您希望參數對象實現的接口協定;以對象的子類和接口的形式定義「裝飾」,接口爲您的特定類實現接口行爲的特定實現(因此實現契約),這樣您就可以實現DoSomething方法的實現每個班級都與這些類別的來源完全分開秒。

這樣做的另一件事是;這意味着如果您將工廠變爲DI容器,則可以在運行時添加新類型;通過在你的工廠容器中注入你希望能夠做些什麼的新類型,只要你有一個你想要採取的動作的實現定義爲一個從你的接口派生出來的類並從那個類, 你很好。如果實施完整的AOP方法,您甚至可以在運行時定義行爲而不必實施派生類;定義你的界面,定義你的行爲,並參數化派生類的實現,在運行時將你想要的行爲與你傳入的對象組合在一起。但是這很複雜...... :-)

順便說一下,Spring AOP對於這個東西非常棒。我讀過它。

0

我同意史蒂文,也是這個問題的上下文提醒我雙重調度問題,因此訪問者模式可能是正確的解決方案。但是,顯然您的層次結構缺少一些接口定義。