Шаблон посетителей против даункастинга с ограничением на тип входа

У меня разные посетители для определенных типов объектов. У меня проблема с реализацией общего интерфейса, который можно использовать для всех типов. Какую архитектуру лучше использовать в этой ситуации? Я придумал 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);
}
};

1

Решение

Ответ явно зависит от того, что вы пытаетесь достигать Вот.
Шаблон посетителя используется для работы с составными объектами, такими как, например, деревья и называет себя подобъектами этой композиции. В вашем примере это был бы текст, содержащий тексты и изображения, содержащие тексты и изображения … Это явно не имеет особого смысла, так что если вы являются на самом деле, работая с текстами и изображениями, посетитель может оказаться не тем, что вам нужно, и вам следует предоставить больше информации о том, чего вы пытаетесь достичь.

На ваши разные коды:

  1. выглядит хорошо, это действительная реализация посетителя. Посетитель будет работать с любым композитом, который не содержит изображений.
  2. выглядит плохо, из-за dynamic_cast, Все дело в шаблоне посетителя в том, чтобы избежать таких бросков, и этот не расширяемый. Рассмотрим, например, еще несколько типов в вашей иерархии объектов, например звуковые файлы, видео и тд. с помощью dynamic_cast здесь вам не сильно поможет. И если вы хотите поддерживать только один тип объекта, вам не нужен посетитель.
  3. выглядит еще хуже. Ваш VisitorDispatcher наследуется от Visitor<Text> а также содержит Visitor<Text> также. В лучшем случае это странный дизайн.
2

Другие решения

Обратите внимание, как ваш Visitor класс нуждается в информации о производных классах Object, Вы хотите сделать полиморфизм, но вы застряли, создав отдельного посетителя для каждого нового производного Object, Для того, чтобы сделать эту работу, вам нужно иметь свой Object быть более универсальным. Я предполагаю, что вы пытаетесь создать какой-то механизм рисования Objects на экране, поэтому каждый объект также нуждается virtual int width() = 0 а также virtual int height() = 0 которые реализуются производными. Абстрактный метод virtual void draw() = 0 за Object тогда также будет необходимо. Таким образом, вам не нужно class TextVisitor а также не class ImageVisitor, Visitor можно просто позвонить object->draw() на каждом Object это посещает.

0

По вопросам рекламы [email protected]