반응형
커맨드 패턴에서, 시스템의 모든 변경 이력을 기록해 과거의 어떤 지점으로든 상태를 되돌릴 수 있는 내용을 살펴 보았습니다.
모든 임의의 과거가 아니라 필요한 때 특정 시점으로 되돌릴 수만 있으면 충분한 경우가 있습니다.
메멘토 패턴은 바로 이런 경우 이며 특정 시점의 시스템 상태를 전용 객체에 저장하여 리턴합니다.
이렇게 저장된 객체를 이용하여 저장되어 있던 상태로 되돌릴 수 있습니다.
은행 계좌
다음은 BankAccount 클래스의 정의입니다.
class BankAccount
{
int balance = 0;
public:
explicit BankAccount(const int balance)
: balance(balance)
{
}
Memento deposit(int amount) // 예금 처리후 메멘토 객체를 반환
{
balance += amount;
return { balance };
}
void restore(const Memento& m)
{
balance = m.balance;
}
};
BankAccount::deposit 함수는 예금을 처리후 메멘토 객체를 반환합니다.
Memento 객체는 계좌를 Memento에 저장된 상태로 되돌릴 때 사용될 수 있습니다.
Memento 클래스는 아래와 같이 쉽게 구현됩니다.
class Memento
{
int balance;
public:
Memento(int balance) : balance(balance) {}
friend class BankAccount;
};
다음과 같이 계좌 상태를 기억해 두었다가 되돌릴 수 있습니다.
BankAccount ba{ 100 };
auto m1 = ba.deposit(50); // 150
auto m2 = ba.deposit(25); // 175
// m1로 복구, 잔고 150
ba.restore(m1);
// m2로 복구, 잔고 175
ba.restore(m2);
Undo와 Redo
BankAccount에서 생성되는 Memento를 모두 저장하면 어떻게 될까? 이 경우 커맨드 디자인 패턴의 구현에서와 마찬가지로 되돌리기(undo)와 다시하기(redo) 작업이 가능해집니다.
이제 Memento를 이용해서 Undo/Redo 기능의 구현에 대하여 알아봅겠습니다.
class BankAccount2
{
int balance = 0;
vector<shared_ptr<Memento>> changes;
int current;
public:
explicit BankAccount2(const int balance)
: balance(balance)
{
changes.emplace_back(make_shared<Memento>(balance));
current = 0;
}
shared_ptr<Memento> deposit(int amount)
{
balance += amount;
auto m = make_shared<Memento>(balance);
changes.push_back(m);
++current;
return m;
}
void restore(const shared_ptr<Memento>& m)
{
if (m)
{
balance = m->balance;
changes.push_back(m);
current = changes.size() - 1;
}
}
shared_ptr<Memento> undo()
{
if (current > 0)
{
--current;
auto m = changes[current];
balance = m->balance;
return m;
}
return{};
}
shared_ptr<Memento> redo()
{
if (current + 1 < changes.size())
{
++current;
auto m = changes[current];
balance = m->balance;
return m;
}
return{};
}
};
restore 구현이 조금 달라 졌습니다. 복구 자체도 기록하여 이 동작을 다시 되돌릴 수도 있도록 하였습니다.
undo/redo 구현은 비슷 합니다. current 위치를 변경하여 원하는 위치의 memento를 얻어 옵니다.
이제 사용 예제를 살펴보겠습니다.
BankAccount2 ba{ 100 };
ba.deposit(50); // 150
ba.deposit(25); // 175
ba.undo(); // 150
ba.undo(); // 100
ba.redo(); // 150
ba.undo(); // 100
코드 참고 : https://cpp-design-patterns.readthedocs.io/en/latest/
'프로그래밍 일반 > 디자인 패턴' 카테고리의 다른 글
관찰자 패턴(Observer Pattern) (0) | 2020.03.04 |
---|---|
Null 객체 (0) | 2020.03.04 |
커맨드 패턴(Command Pattern) (0) | 2020.03.04 |
중재자 패턴(Mediator Pattern) (0) | 2020.03.04 |
반복자 패턴(Iterator Pattern) (0) | 2020.03.04 |