У меня разные посетители для определенных типов объектов. У меня проблема с реализацией общего интерфейса, который можно использовать для всех типов. Какую архитектуру лучше использовать в этой ситуации? Я придумал 3 разных решения, но все они кажутся мне безобразными: (некоторые вещи, такие как виртуальные деструкторы, для простоты опущены)
class IObject {
virtual void Accept(IVisitor& visior) = 0;
};
class Text: IObject {
void Accept(IVisitor& visitor) {
visitor.Visit(*this);
}
};
class Image: IObject {
void Accept(IVisitor& visitor) {
visitor.Visit(*this);
}
};
class IVisitor {
virtual void Visit(Text& text) = 0;
virtual void Visit(Image& image) = 0;
};
class TextVisitor: IVisitor {
void Visit(Text& text) {
// Do some stuff with text
}
void Visit(Image& image) {
// Image not supported, throw exception
}
};
ИЛИ ЖЕ
class IObject {};
class Text: IObject {};
class Image: IObject {};
class IVisitor {
virtual void Visit(IObject& object) = 0;
};
class TextVisitor: IVisitor {
void Visit(IObject& object) {
Text& text = dynamic_cast<Text&>(object);
// Do some stuff with text
}
};
ИЛИ ЖЕ
template <typename T>
class IVisitor {
virtual void Visit(T& object) = 0;
};
class TextVisitor: IVisitor<Text> {
void Visit(Text& text) {
// Do some stuff
}
};
class ImageVisitor: IVisitor<Image> {
void Visit(Image& image) {
// Do some stuff
}
};
class ITextImagelVisitor: IVisitor<Text>, IVisitor<Image> {};
class VisitorDispatcher: ITextImageVisitor {
void Visit(Text& text) {
text_visitor_->Visit(text);
}
void Visit(Image& image) {
image_visitor_->Visit(image);
}
std::shared_ptr<IVisitor<Text>> text_visitor_;
std::shared_ptr<IVisitor<Image>> image_visitor_;
};
class IObject {
virtual void Accept(ITextImageVisitor& visior) = 0;
};
class Text: IObject {
void Accept(ITextImageVisitor& visitor) {
visitor.Visit(*this);
}
};
class Image: IObject {
void Accept(ITextImageVisitor& visitor) {
visitor.Visit(*this);
}
};
Ответ явно зависит от того, что вы пытаетесь достигать Вот.
Шаблон посетителя используется для работы с составными объектами, такими как, например, деревья и называет себя подобъектами этой композиции. В вашем примере это был бы текст, содержащий тексты и изображения, содержащие тексты и изображения … Это явно не имеет особого смысла, так что если вы являются на самом деле, работая с текстами и изображениями, посетитель может оказаться не тем, что вам нужно, и вам следует предоставить больше информации о том, чего вы пытаетесь достичь.
На ваши разные коды:
dynamic_cast
, Все дело в шаблоне посетителя в том, чтобы избежать таких бросков, и этот не расширяемый. Рассмотрим, например, еще несколько типов в вашей иерархии объектов, например звуковые файлы, видео и тд. с помощью dynamic_cast
здесь вам не сильно поможет. И если вы хотите поддерживать только один тип объекта, вам не нужен посетитель.VisitorDispatcher
наследуется от Visitor<Text>
а также содержит Visitor<Text>
также. В лучшем случае это странный дизайн.Обратите внимание, как ваш Visitor
класс нуждается в информации о производных классах Object
, Вы хотите сделать полиморфизм, но вы застряли, создав отдельного посетителя для каждого нового производного Object
, Для того, чтобы сделать эту работу, вам нужно иметь свой Object
быть более универсальным. Я предполагаю, что вы пытаетесь создать какой-то механизм рисования Object
s на экране, поэтому каждый объект также нуждается virtual int width() = 0
а также virtual int height() = 0
которые реализуются производными. Абстрактный метод virtual void draw() = 0
за Object
тогда также будет необходимо. Таким образом, вам не нужно class TextVisitor
а также не class ImageVisitor
, Visitor
можно просто позвонить object->draw()
на каждом Object
это посещает.