Материалы книги получены с http://www.itlibitum.ru/
Стеки образов
Для многоуровневой отмены вам может понадобиться стек предыдущих образов. Один из вариантов реализации - хранить стек в каждом указателе образов. В следующем фрагменте предполагается, что у вас имеется параметризованный класс Stack с функциями Empty(), Push(), Pop() и DeleteAll().
Функция Pop() возвращает верхний элемент стека или NULL, если стек пуст. Функция DeleteAll() опустошает стек и уничтожает все объекты по мере их извлечения. Каждый указатель хранит стек предыдущих образов. Если стек пуст, значит, образы не создавались. Если стек не пуст, в его нижней части находится исходный объект. Функция Rollback() находит и восстанавливает этот объект. Конструктор копий и оператор = работают так же, как и в описанном выше простейшем указателе образов.
template <class Type>
class ImageStackPtr {
private:
Type* current; // Текущий образ, предоставляемый клиенту
Stack<Type> history; // Предыдущие образы
public:
ImageStackPtr() : current(new Type) {}
ImageStackPtr(const ImageStackPtr<Type>& ip)
: current(new Type(*(ip.current))) {}
~ImageStackPtr() { delete current; }
ImageStackPtr<Type>& operator=(const ImageStackPtr<Type>& ip)
{
if (this != &ip) {
history.DeleteAll();
delete current;
current = new Type(*(ip.current));
}
return *this;
}
void PushImage()
{
history.Push(current);
current = new Type(*current);
}
void Commit() { history.DeleteAll(); }
void PopImage() // Вернуться на один уровень
{
if (!history.Empty()) {
delete current;
current = history.Pop();
}
}
void Rollback() // Вернуться к самому старому образу
{
Type* old = history.Pop();
Type* oldere = NULL;
if (old != NULL) { // Хотя бы один раз
while ((older = history.Pop()) != NULL) {
delete old;
old = older;
}
delete current;
current = old;
}
}
Type* operator->() const { return current; }
};
Хранение отдельного стека в каждом указателе оправданно для транзакций, в которых участвует небольшое количество объектов. Но если одной транзакции приходится отслеживать множество обновляемых объектов, кучу мелких стеков лучше объединить в один большой. Мы сделаем это позднее, когда речь пойдет о транзакциях.
Назад Содержание Далее
|