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