2010-03-27 47 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; 
}; 

但是这将意味着所有的方法将每个添加的扩展调用。例如。某些附加扩展中的空方法不会加载任何内容,也不会绘制任何内容。