2012-10-18 42 views
3

返回派生類實例的標題可能不清楚,但請看看下面的模式從基類

public abstract class Animal 
{ 

    public abstract Dog GetDog { get; } 

    public abstract Cat GetCat { get; } 

} 

public class Dog : Animal 
{ 

    public override Dog GetDog { 
     get { return this; } 
    } 

    public override Cat GetCat { 
     get { return null; } 
    } 

} 

這被認爲是一個不好的做法,在基類的屬性,返回派生類型。或者我應該這樣做

public abstract AnimalTypeEnum AnimalType { get; } 

編輯:根據意見,我想我應該是什麼,我想實現更清晰。 DogCat類的新實例將由基於特定標準的單獨函數創建,然後將返回Animal類型給調用者。調用方法將檢查返回的實例的類型並相應地使用它。

public Animal CreateAnimal(string path) 
{ 

    //Process the document in path and create either a new instance of dog or cat 

    Dog dg = new Dog(); 

    return dg; 

} 
+1

什麼是你在做這個終極目標是什麼? –

+0

@ user1556110這並沒有真正回答這個問題。這些方法將如何被實際使用? – Servy

+1

好的...但有什麼意義?狗不應該有一個方法來獲得一隻貓,即使它返回null。 「動物狗=新狗()」有什麼問題? –

回答

5

調用方法將檢查返回的實例的類型並相應地使用它。

這是你的問題。它的代碼味道需要做到這一點。你應該能夠把它當作一個對象來對待,而不是以不同的方式對待狗和貓。

如果您需要顯示任一動物的內容,則覆蓋兩個類的ToString方法,並在動物上調用ToString。如果您需要知道狗或貓的名字,請將Name財產添加到Animal。如果可能的話,你應該在這裏使用多態,這樣無論使用什麼對象,它都只是一個Animal,並且簡單地涉及由於同一方法的不同實現而發生的不同事情。

如果你真的,真的需要知道Animal是否是DogCat,那麼你可以使用isas運營商;您不需要添加您在OP中顯示的所有代碼。

+0

基類具有許多對派生類型都通用的功能,派生類型將它擴展多一點。當調用CreateAnimal函數時,需要動態創建Cat類型或Dog類型,並且無法知道需要創建哪種類型。所以我真的需要返回最低保證類型,並提供選項,如果他們想要多一點。 – swiftgp

+1

@ user1556110是的,'CreateAnimal'方法很好;我不是建議你改變它。我在說,你應該能夠做任何你需要做的事情''動物'返回沒有做一個'貓'或'狗'實例的結果返回。雖然可能會有這樣的情況,你真的不能這樣做,在走下這條路之前,你應該很確定。如果你真的走上了這條路,正如我所說的那樣,你應該使用「is」或「as'而不是你創建的結構。 – Servy

+0

@ user1556110 - 即使假設你需要知道它是否是一個'Cat'或者'Dog',你可以用'is'來代替你想用的任何測試。 – Bobson

5

你真的做錯了。

更好的事情是有一個單一的方法。

public abstract Animal getAnimal(); 

任何派生類將知道如何返回自己。我希望這是有道理的。但是,我不認爲你會想要返回一個動物。沒有意義。

Animal dog = new Dog() ; 
dog.getAnimal(); 

迷惑吧?

你可以有動物/列表的陣列,通過收集和重複檢查,像這樣:

if(animal is Dog) 

不過還是要檢查的類型。如果你想使用一個基類,使它有意義並且暴露一個通用的方法。

-2

讓屬性返回它們被調用的對象似乎不是很有用。

也許你只是在尋找一種方式從超類下降到子類?如果是這樣,只需使用轉換:

Animal a = new Cat(); 

try 
{ 
    Dog d = (Dog)a; 
} 
catch (InvalidCastException) 
{ 
    try 
    { 
     Cat c = (Cat)a; 
    } 
    catch (InvalidCastException) 
    { 
    } 
} 
+4

您不應該使用控制流的異常。 'is'和'as'被設計來做到這一點,而不會產生異常。 – Servy

+0

創造性的解決方案,但有點過分:) – lordkain

+0

同意@Servy,這是一個糟糕的設計。然而,你現在可以通過使用switch語句模式匹配來實現非常類似的功能(沒有所有的try/catch廢話)。 –

1

這是一個非常淺的設計,因爲它違反了Open-Closed principle。你希望你的課堂可以開放,但不適合修改。 如果明天你想添加其他課程會發生什麼?

public class Donkey : Animal 
{ 
} 

你將不得不去改變基類,所以它有一個屬性GetDonkey。 你也必須去改變這一切,用你的類的類,添加if (animal.GetDonkey == null)

你應該做的是使用工廠設計模式是這樣的:

public static class AnimalFactory 
{ 
    public static Dog GetDog() 
    { 
    return new Dog(); 
    } 

    public static Cat GetCat() 
    { 
    return new Cat(); 
    } 
} 

,或者你應該使用虛擬方法建議使用@Lews Therin

+0

你提到那裏不應該有一個GetDonkey(),但你有一個GetDog()? – jaxxbo

10

如果你只想要你是從你獲得的動物可以做到這一點:

public abstract class Animal<T> where T: Animal<T> 
{ 
    public T GetAnimal 
    { 
     get { return (T)this; } 
    } 
} 

public class Dog : Animal<Dog> 
{ 
} 

public class Cat : Animal<Cat> 
{ 
} 

public class Giraffe : Animal<Giraffe> 
{ 
} 

你調用這個方法:

var cat = new Cat(); 
var dog = new Dog(); 
var giraffe = new Giraffe(); 
Cat cat2 = cat.GetAnimal; 
Dog dog2 = dog.GetAnimal; 
Giraffe giraffe2 = giraffe.GetAnimal; 
+0

儘管我認爲這是C#泛型給我們的最好的解決方案,但請注意,可以使用'public class Rat:Animal {}',這樣可以很好地編譯,然後在調用'new Rat()時炸燬。GetAnimal '... –

+0

好的解決方案。謝謝! –