У меня есть ситуация, которая в теории, возможно, идеально подходит для составных и итерационных шаблонов проектирования, но проблема, с которой я сталкиваюсь с этими шаблонами, заключается в том, что никто не может получить доступ к базовой структуре данных, которая может нарушить условия сделки.
Конечно, у меня может быть магазин в торговом центре в городе в стране, и это создает взаимосвязь между собой, и если я создаю из него составной шаблон, я могу запускать общие методы для всех объектов (по большей части), например, в какое время магазин / торговый центр открывается и закрывается, но на самом деле нам нужно больше, чем это.
Возьмем, к примеру, простую задачу загрузки такой составной структуры из уже сохраненного файла в древовидный элемент управления. Теперь мы даже не знаем, какой компонент является чем-то, поэтому мы не можем даже определить, должен ли компонент быть родительским, родным или дочерним в дереве. По сути, нам нужно сделать какую-то проверку типа, чтобы выяснить, против какого составного шаблона в первую очередь. Это особенно верно для внешнего итератора.
Сначала казалось, что эти два паттерна в комбинации имеют больший потенциал, но теперь они кажутся малопригодными.
Я пытаюсь найти истинное обоснование этих двух закономерностей. Где это может быть использовано лучше, чем простой пример учебника, как Print()
cost()
функции. Прав ли я в том, что составная часть должна быть приведена назад, чтобы заполнить древовидный элемент управления, чтобы отразить иерархию составной части при загрузке из файла?
Вам не нужно итератор, тебе необходимо посетитель.
Итераторы для объектов, которые являются однородными; ваши объекты определенно не равномерная. Более того, композитный имеет тенденцию работать лучше, когда объекты используются единообразно. Один классический пример — выражения, которые вы вычисляете; другая — это геометрические фигуры, которые вы отображаете на экране. Опять же, ваш случай плохо подходит для классической комбинированной модели, потому что у магазинов и округов не так много общего.
К счастью, посетитель все исправляет: определите класс посетителя, который знает, что делать с городом, округом, торговым центром и магазином. Сделайте каждый из этих классов «посещаемыми», и расположите их в композит. Теперь объединяющим свойством ваших классов является то, что каждый из них можно посетить. Листовые классы перезвонят посетителю и передадут себя в качестве аргумента. Классы веток сначала проходят сами, а затем передают посетителя всем их компонентам. Это позволило бы вам пройтись по всей иерархии красивым и чистым способом.
class County;
class City;
class Mall;
class Shop;
struct ShoppingVisitor {
virtual void visitCounty(const County& county);
virtual void visitCity(const City& city);
virtual void visitMall(const Mall& mall);
virtual void visitShop(const Shop& shop);
};
struct ShoppingVisitable {
virtual void accept(ShoppingVisitor& visitor) const;
};
class County : public ShoppingVisitable {
vector<ShoppingVisitable*> children;
public:
virtual void accept(ShoppingVisitor& visitor) const {
visitor.visitCounty(*this);
for (int i = 0; i != children.size() ; i++) {
children[i]->accept(visitor);
}
}
};
class City : public ShoppingVisitable {
vector<ShoppingVisitable*> children;
public:
virtual void accept(ShoppingVisitor& visitor) const {
visitor.visitCity(*this);
for (int i = 0; i != children.size() ; i++) {
children[i]->accept(visitor);
}
}
};
struct Mall : public ShoppingVisitable {
virtual void accept(ShoppingVisitor& visitor) const {
visitor.visitMall(*this);
}
};
struct Shop : public ShoppingVisitable {
virtual void accept(ShoppingVisitor& visitor) const {
visitor.visitShop(*this);
}
};
Пример stl-совместимого внешнего итератора композита, см. Это Композиционно-итератор хранилище на github. Это прямой итератор. * iter возвращает базовый класс, Node.
Композит является примером файловой системы из Pattern Hatching. Смотрите стр. 25 из них слайды для описания и диаграмм классов. Справочник является составным. Конечные узлы — это экземпляры File, а базовым классом компонента для обоих является Node.
пример
Directory::iterator iter_current = top.begin();
Directory::iterator iter_end = top.end();
for (;iter_current != iter_end; ++iter_current) {
Node &node = *iter_current;
cout << "[address: " << hex << &node << "] " << node.getName();
if (dynamic_cast<Directory*>(&node) ) {
cout << " is a Directory ";
} else {
cout << " is a File ";
}
cout << endl;
}