【发布时间】:2019-04-25 06:50:44
【问题描述】:
问题
我遇到了一个简单的问题,但我无法为它想出合适的 OOD。
我有什么:
- 基类
- 子类添加新方法
foo() - 指向基类实例的指针列表
我需要什么:
我需要遍历这个列表并调用foo() 来获取支持此方法的对象,即上述子类的对象(或派生自)。或者一般来说,我需要通过指向基类的指针列表对子类进行“无异味”多态访问。
示例代码
class Entity {
// ...
// This class contains methods also needed by subclasses.
};
class SaveableEntity : public Entity {
public:
virtual void save() = 0;
};
// SaveableEntity has multiple subclasses with specific save() implementations.
std::vector<Entity *> list;
for (Entity *entity : list) {
// Here I need to save() the descendants of a SaveableEntity type.
}
我想出了一些想法,但我觉得它们都不对。以下是其中一些:
方法一:dynamic_cast
由于有些元素是可保存的,有些则不是,我看到的最明显的方式是动态转换:
std::vector<Entity *> list;
for (Entity *entity : list) {
auto saveable = dynamic_cast<SaveableEntity *>(entity);
if (saveable) {
saveable->save();
}
}
但是,在这种情况下使用 dynamic_cast 看起来很糟糕(如果我错了,请纠正我)。另外,这种做法很容易导致违反LSP。
方法2:将save()移动到基类
我可以删除SaveableEntity 并将save() 方法移动到基础Entity。但是,这使我们实现了虚拟方法:
class Entity {
virtual void save() {
// Do nothing, override in subclasses
}
};
这消除了dynamic_cast 的使用,但虚拟方法似乎仍然不正确:现在基类包含与它完全无关的信息(save() 方法)。
方法 3:应用设计模式
-
策略模式:
SaveStrategy类及其子类,如NoSaveStrategy、SomeSaveStrategy、SomeOtherSaveStrategy等。同样,NoSaveStrategy的存在让我们回到了之前方法的缺陷: 基类必须知道其子类的具体细节,这似乎是一个糟糕的设计。 -
Proxy 或 Decorator 模式可以轻松封装
dynamic_cast,但这只会隐藏不需要的代码,并不能摆脱糟糕的设计本身。 - 添加一些composition-over-inheritance 层,等等等等...
问题
也许我遗漏了一些明显的解决方案,或者所描述的方法(1 或 2)在这种特定情况下并不像我看到的那样糟糕和难闻。
那么什么样的设计方法适合这种情况呢?
【问题讨论】:
-
你仍然可以实现一个纯虚函数。这或多或少会使其成为默认行为。不过我不确定是否有臭味:-/
-
这个角度看你的问题:基类接口不支持foo。而且您想通过所述接口(通过基类指针访问真实对象)做一些它不支持的事情( foo )。
标签: c++ oop inheritance design-patterns polymorphism