То, что вы делаете, напоминает шаблоны Composite и Visitor . Эти две модели хорошо сочетаются друг с другом, поэтому кажется, что вы на правильном пути.
Для реализации составного шаблона назначьте следующие роли (см. Диаграмму UML составного шаблона):
- Лист ->
Field
- Композит ->
Record
- Компонент -> Абстрактный базовый класс
Field
и Record
(не могу придумать хорошее имя)
Операции с компонентами, вызываемые для составных типов, рекурсивно передаются всем дочерним элементам (листьям и другим вложенным составным типам).
Чтобы реализовать шаблон Visitor, перегрузите operator()
в ваших классах функторов для каждого подтипа Компонента (Поле и Запись).
Я рекомендую вам получить книгу Design Patterns из книги "Банды четырех", которая лучше объясняет эти концепции и углубляется в детали, чем я могу .
Вот пример кода для поднятия аппетита:
#include <iostream>
#include <vector>
#include "boost/shared_ptr.hpp"
#include "boost/foreach.hpp"
class Field;
class Record;
struct Visitor
{
virtual void operator()(Field& field) = 0;
virtual void operator()(Record& field) = 0;
};
class Component
{
public:
virtual bool isLeaf() const {return true;}
virtual void accept(Visitor& visitor) = 0;
};
typedef boost::shared_ptr<Component> ComponentPtr;
class Field : public Component
{
public:
explicit Field(int value) : value_(value) {}
void accept(Visitor& visitor) {visitor(*this);}
int value() const {return value_;}
private:
int value_;
};
class Record : public Component
{
public:
typedef std::vector<ComponentPtr> Children;
Record(int id) : id_(id) {}
int id() const {return id_;}
Children& children() {return children_;}
const Children& children() const {return children_;}
bool isLeaf() const {return false;}
void accept(Visitor& visitor)
{
visitor(*this);
BOOST_FOREACH(ComponentPtr& child, children_)
{
child->accept(visitor);
}
}
private:
int id_;
Children children_;
};
typedef boost::shared_ptr<Record> RecordPtr;
struct OStreamVisitor : public Visitor
{
OStreamVisitor(std::ostream& out) : out_(out) {}
void operator()(Field& field) {out_ << "field(" << field.value() << ") ";}
void operator()(Record& rec) {out_ << "rec(" << rec.id() << ") ";}
std::ostream& out_;
};
int main()
{
RecordPtr rec(new Record(2));
rec->children().push_back(ComponentPtr(new Field(201)));
rec->children().push_back(ComponentPtr(new Field(202)));
RecordPtr root(new Record(1));
root->children().push_back(ComponentPtr(new Field(101)));
root->children().push_back(rec);
OStreamVisitor visitor(std::cout);
root->accept(visitor);
}
В Record вы можете захотеть предоставить методы для манипулирования / доступа к дочерним элементам вместо возврата ссылки на базовый дочерний вектор.