Проблема
Я столкнулся с простой проблемой, хотя не могу придумать для нее подходящее OOD.
Что у меня есть:
- Базовый класс
- Подкласс, добавляющий новый метод
foo()
- Список указателей на экземпляры базового класса
Что яneed:
Мне нужно перебрать этот список и вызвать 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.
}
Я пришел с некоторыми идеями,однако ни один из них не кажется мне правильным.Вот некоторые из них:
Метод 1: dynamic_cast
Поскольку некоторые элементы являются сохраняемыми, а некоторые нет, наиболее очевидный способ, который я вижу, - это динамическое приведение:
std::vector<Entity *> list;
for (Entity *entity : list) {
auto saveable = dynamic_cast<SaveableEntity *>(entity);
if (saveable) {
saveable->save();
}
}
Однако использование dynamic_cast
выглядит как плохой OOD в этой ситуации (поправьте меня, если я ошибаюсь).Кроме того, этот подход может легко привести к нарушению 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
возвращает нас к недостатку предыдущего метода: базовый класс должен знать конкретные детали своего подкласса, что выглядит как плохой дизайн. - Добавитьнекоторые слои композиции-наследования и т. д. и т. д. ...
Вопрос
Возможно, я упускаю какое-то очевидное решение или, возможно, описанные методы (1 или2) не так плохо и вонючий в этом конкретном мошенничестветекст, как я их вижу.
Так какой подход к дизайну подходит в такой ситуации?