CODESAMPLE

Snapshot - C++

Share on:

The Snapshot pattern allows capturing and restoring the internal state of an object. It’s useful for implementing features like undo/redo, transaction rollback, or saving game states. This implementation uses a separate Snapshot class to hold the state, and a Memento class to provide a controlled interface for accessing it. The Originator class creates snapshots and restores from them. This approach adheres to C++’s emphasis on encapsulation and separation of concerns, using classes to manage state and access. Copying the state within the snapshot ensures immutability, crucial for reliable restoration.

#include <iostream>
#include <vector>
#include <algorithm>

// Memento interface
class Memento {
public:
  virtual ~Memento() = default;
  virtual std::vector<int> getState() const = 0;
};

// Concrete Memento (Snapshot)
class Snapshot : public Memento {
private:
  std::vector<int> state_;

public:
  Snapshot(const std::vector<int>& state) : state_(state) {}

  std::vector<int> getState() const override { return state_; }
};

// Originator
class Originator {
private:
  std::vector<int> data_;

public:
  void setData(const std::vector<int>& data) { data_ = data; }
  std::vector<int> getData() const { return data_; }

  Memento createSnapshot() const {
    return Snapshot(data_);
  }

  void restoreFromSnapshot(const Memento& memento) {
    data_ = memento.getState();
  }
};

// Caretaker
class Caretaker {
private:
  std::vector<Memento*> snapshots_;

public:
  void addSnapshot(Memento* snapshot) {
    snapshots_.push_back(snapshot);
  }

  Memento* getSnapshot(int index) const {
    if (index >= 0 && index < snapshots_.size()) {
      return snapshots_[index];
    }
    return nullptr;
  }
};

int main() {
  Originator originator;
  Caretaker caretaker;

  originator.setData({1, 2, 3});
  std::cout << "Original state: ";
  for (int val : originator.getData()) {
    std::cout << val << " ";
  }
  std::cout << std::endl;

  caretaker.addSnapshot(originator.createSnapshot());

  originator.setData({4, 5, 6});
  std::cout << "Modified state: ";
  for (int val : originator.getData()) {
    std::cout << val << " ";
  }
  std::cout << std::endl;

  Memento* snapshot = caretaker.getSnapshot(0);
  if (snapshot) {
    originator.restoreFromSnapshot(*snapshot);
    std::cout << "Restored state: ";
    for (int val : originator.getData()) {
      std::cout << val << " ";
    }
    std::cout << std::endl;
  }

  return 0;
}