Идиомы и стили С++ | страница 33



-указатель. Кладем в него два указателя - один на текущий объект, а второй - на объект, представляющий его предыдущее состояние, и три функции - старт, закрепление, отмена.

>#include ‹iostream.h›

>// Некий скромный класс.

>class CSomeClass {

>public:

> int x;

> int y;

>};


>// Его оплетка: smart-pointer с поддержкой отмены.

>class CSimpleTr {

>public:

> CSomeClass* that; // текущее значение

> CSomeClass* previos; // предыдущее значение

>public:

> // конструктор-деструктор-присваивание-копирование

> CSimpleTr(): previos(NULL), that(new CSomeClass) {}

> CSimpleTr(const CSimpleTr& _st): that(new CSomeClass(*(_st.that))), previos(NULL) {}

> ~CSimpleTr() {delete that; delete previos;}

> CSimpleTr& operator=(const CSimpleTr& _st) {

>  if (this!=&_st) {

>   delete that;

>   that = new CSomeClass(*(_st.that));

>  }

>  return *this;

> }

> // начало транзакции

> void BeginTrans() {

>  delete previos;

>  previos = that;

>  that = new CSomeClass(*previos);

> }

> // закрепление

> void Commit() {

>  delete previos;

>  previos = NULL;

> }

> // отмена транзакции

> void Rollback() {

>  if (previos != NULL) {

>   delete that;

>   that = previos;

>   previos = NULL;

>  }

> }

> // реализация указателя

> CSomeClass* operator-›() { return that; }

>};


>int main (void) {

> // проверим быстренько

> CSimpleTr lvPair;

> lvPair-›x = 5;

> lvPair-›y = 8;

> lvPair.BeginTrans();

> lvPair-›x = 7;

> lvPair-›y = 11;

> lvPair.Rollback();

> lvPair.BeginTrans();

> lvPair-›x = 7;

> lvPair-›y = 11;

> lvPair.Commit();

> return 0;

>}

Что может быть проще? Семантика значений, очевидно. Классы должны иметь полный набор обязательных функций, как обычно; в нашем случае класс CSomeClass больно уж тривиален, поэтому сойдет и так. Класс CSimpleTr имеет смысл переписать в виде шаблона, если не хотите его заново переписывать для каждого нового клиента, да еще добавить функцию isStarted(). Функциональность на Ваш вкус и фантазию. MTS, например, восстановит отмененную транзакцию, если Вы после отмены сделаете закрепление: SetAbort(); SetComplete(); сработает так, как будто SetAbort(); не было вовсе.

Шаг 23 - Классы объектов, поддерживающие транзакции. Продолжение.

Раз уж взялись, что мешает вставить в наш умный указатель с поддержкой отмены не один, а несколько предыдущих состояний объекта? Ничего. Только чтобы потом несколько раз не переделывать, решим несколько чисто технических моментов:

1. Какую структуру будем использовать в качестве коллекции состояний? Можно взять стек, можно кольцевой буфер, а можно и карту (словарь, хэш-таблицу); стек явно проще, зато за кольцевым буфером можно не следить вообще, пусть устаревшие состояния пропадают бесследно (конечно по желанию).