2010-03-27 43 views
1

這是我在這裏的第一個問題:)多態性問題:如何檢查派生類的類型?

我知道我不應該檢查對象類型,而是使用dynamic_cast,但這並不能解決我的問題。我有類擴展名和接口,稱爲IExtendable和IInitializable,IUpdatable,ILoadable,IDrawable(最後四個基本相同)。如果Extension實現了IExtendable接口,它可以使用不同的擴展對象進行擴展。

問題是我想允許實現IExtendable的擴展只擴展到實現與原始擴展相同接口的擴展。

你可能不unerstand那件事情,所以我嘗試用代碼來解釋它:

class IExtendable 
{ 
public: 
IExtendable(void); 

void AddExtension(Extension*); 
void RemoveExtensionByID(unsigned int); 

vector<Extension*>* GetExtensionPtr(){return &extensions;}; 
private: 
vector<Extension*> extensions; 
}; 

class IUpdatable 
{ 
public: 
IUpdatable(void); 
~IUpdatable(void); 

virtual void Update(); 
}; 

class Extension 
{ 
public: 
Extension(void); 
virtual ~Extension(void); 

void Enable(){enabled=true;}; 
void Disable(){enabled=false;}; 

unsigned int GetIndex(){return ID;}; 

private: 
bool enabled; 
unsigned int ID; 

static unsigned int _indexID; 
}; 

現在想象一下,我創建擴展這樣的案例:

class MyExtension : public Extension, public IExtendable, public IUpdatable, public IDrawable 
{ 
public: 
    MyExtension(void); 
    virtual ~MyExtension(void); 

    virtual void AddExtension(Extension*); 
    virtual void Update(); 
    virtual void Draw(); 
}; 

而且我想允許此類僅使用實現相同接口(或更少)的擴展來擴展自己。例如,我希望它能夠實現IUpdatable的Extension;或IUpdatable和IDrawable;但例如不是實現ILoadable的擴展。 我想這樣做,因爲例如, Update()將在一些實現了IExtendable和IUpdateable的擴展上被調用,它也會在擴展這個擴展的擴展上被調用。

所以,當我添加一些Extension to Extension來實現IExtendable和一些IUpdatable,ILoadable ...我不得不檢查是否要添加的Extension也實現了這些接口。所以在IExtendable :: AddExtension(Extension *)中,我需要這樣做:

void IExtendable::AddExtension(Extension* pEx) 
{ 
bool ok = true; 
// check wheather this extension can take pEx 
// do this with every interface 
if ((*pEx is IUpdatable) && (*this is_not IUpdatable)) 
ok = false; 

if (ok) this->extensions.push_back(pEx); 

} 

但是怎麼樣?任何想法什麼是最好的解決方案?我不想使用dynamic_cast並查看它是否返回空值...謝謝

回答

6

您應該重新考慮您的設計。如果您需要這種行爲,可能會引入IUpdateExtendableIDrawExtendable

當前方法不好的原因是它違反了Liskov Substitution Principle。你基本上是說「這個對象充當IExtendable,但它確實沒有,除非......」如果一個類實現了一個接口,那麼它確實應該可以通過該接口使用,而不需要任何條件。如果不是,這是一個等待發生的維修噩夢。

+0

謝謝,但我真的沒有看到IUpdateExtendable如何解決我的問題 – Martin 2010-03-27 21:24:05

+0

@malymato:如果您爲每個「操作」創建了一個單獨的界面,那麼您的工作可以檢查該特定界面 - 不要嘗試去處理單個IExtendable接口。 – 2010-03-27 22:56:49

0

只是一個直覺,但取決於你的擴展正在做什麼,visitor-pattern可能會幫助你。您可能還需要閱讀decorator模式。

+0

謝謝,但由於我沒有經驗豐富的程序員,這些模式對我來說似乎相當複雜 – Martin 2010-03-27 20:54:56

+0

如果您不是經驗豐富的程序員,並且您正在嘗試執行上述操作,那麼您將會搞亂設計並且後悔不已它後來。 – rlbond 2010-03-27 21:41:30

+0

我想你是對的,我會用我後來發佈的代碼去......我會將這些接口合併到一個類中。 – Martin 2010-03-27 22:00:09

0

我可以合併到一個類中的所有這些接口,所以我會得到這樣的:

class Extension 
{ 
public: 
Extension(void); 
virtual ~Extension(void); 

void AddExtension(Extension* pEx){extensions.push_back(pEx);}; 

virtual void Initialize() 
{ 
for each (Extension* pEx in extensions) pEx->Initialize(); 
}; 

virtual void Load() 
{ 
for each (Extension* pEx in extensions) pEx->Load(); 
}; 

virtual void Update() 
{ 
for each (Extension* pEx in extensions) pEx->Update(); 
}; 

virtual void Draw() 
{ 
for each (Extension* pEx in extensions) pEx->Draw(); 
}; 

private: 
vector<Extension*> extensions; 
}; 

但是這將意味着所有的方法將每個添加的擴展調用。例如。某些附加擴展中的空方法不會加載任何內容,也不會繪製任何內容。