1. 메멘토 패턴이란?
- 객체를 이전 상태로 되돌릴 수 있는 기능을 제공하는 패턴.
- 객체의 상태 정보를 저장하고 사용자의 필요에 의해 원하는 시점의 데이터를 복원할 수 있는 패턴.
- 캡슐화를 유지하면서 객체 내부 상태를 외부에 저장하는 방법.
2. 메멘토 패턴을 사용하는 경우
- 어떤 객체의 상태를 변경하고, 이 변경 내용을 이후에 취소하거나 이전 상태로 복원하려고 할 때 사용
- 객체의 field, getter, setter들을 직접 접근하는 것이 해당 객체의 캡슐화를 위반할 때 사용
3. 메멘토 패턴의 장점
- 객체의 모든 정보를 외부로 노출시키지 않고 캡슐화를 지킬 수 있다.
- 캡슐화를 위반하지 않고 객체의 상태 스냅샷들을 생성할 수 있다.
- 코드를 단순화 시킬 수 있다.
4. 메멘토 패턴의 단점
- 이전 상태의 객체를 저장하기 위한 Originator가 클 경우 많은 메모리가 필요하다.
- 상태를 저장하고 복구하는데 시간이 오래 걸릴 수 있다.
- CareTaker들이 더 이상 쓸모없는 Memento들을 파괴할 수 있도록 Originator의 수명 주기를 추적해야한다.
5. 코드 구현
1) 구조
- Originator
: 본래의 상태를 가지고 있고 상태를 저장하고 복원하고 싶어하는 객체
- Memento
: Immutable(불변)한 객체로 일정 시점의 Originator의 내부정보를 가지고 있다.
- CareTaker
: Originator의 내부정보를 Memento type으로 가지고 있고 복원을 할 수 있는 객체이다.
2) 소스코드(C#)
using Microsoft.Win32;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http.Headers;
using System.Reflection;
using System.Runtime.CompilerServices;
namespace StudyCSharp
{
// Originator - 현재 state를 가지고 있음, Memento 객체와 Memento 객체 상태를 얻게 함.
public class Originator
{
private string _state;
public string State { get => _state; set => _state = value; }
public Memento saveStateToMemento()
{
return new Memento(_state);
}
public void getStateFromMemento(Memento memento)
{
_state = memento.State;
}
}
// Memento - State를 가진 인스턴스
public class Memento
{
private string _state;
public string State { get => _state; }
public Memento(string state)
{
this._state = state;
}
}
// CareTaker - Memento를 순서대로 저장
public class CareTaker
{
private List<Memento> _mementoList = new List<Memento>();
public List<Memento> MementoList { get => _mementoList; }
public void add(Memento state)
{
_mementoList.Add(state);
}
}
class Program
{
static void Main(string[] args)
{
Originator originator = new Originator();
CareTaker careTaker = new CareTaker();
originator.State = "State # 1";
originator.State = "State # 2";
careTaker.add(originator.saveStateToMemento()); // 2번 상태 저장
originator.State = "State # 3";
careTaker.add(originator.saveStateToMemento()); // 3번 상태 저장
originator.State = "State # 4";
Console.WriteLine("Current State : {0}", originator.State);
Console.WriteLine("-----------------------------------------------------");
originator.getStateFromMemento(careTaker.MementoList[0]);
Console.WriteLine("First saved State : {0}", originator.State);
Console.WriteLine("-----------------------------------------------------");
originator.getStateFromMemento(careTaker.MementoList[1]);
Console.WriteLine("Second saved State : {0}", originator.State);
Console.WriteLine("-----------------------------------------------------");
}
}
}
- 실행 결과
3) 소스코드(C#)
using Microsoft.Win32;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http.Headers;
using System.Reflection;
using System.Runtime.CompilerServices;
namespace StudyCSharp
{
// Originator - Player의 정보를 가지고 있음, 저장 및 불러오기를 실행할 수 있음.
public class Player
{
private int _lv;
private string _job;
public int Lv { get => _lv; }
public string Job { get => _job; }
public PlayerInfo Save()
{
return new PlayerInfo(this._lv, this._job);
}
public void Undo(PlayerInfo playerInfo)
{
this._lv = playerInfo.Lv;
this._job = playerInfo.Job;
}
public void SetInfo(int lv, string job)
{
this._lv = lv;
this._job = job;
}
public void GetInfo()
{
Console.WriteLine("<<현재 상태>>");
Console.WriteLine("현재 레벨 : {0}", this._lv);
Console.WriteLine("현재 직업 : {0}", this._job);
//Console.WriteLine("--------------------------------------------------");
}
}
// Memento - Player의 정보를 가지고 있음.
public class PlayerInfo
{
private int _lv;
private string _job;
public int Lv { get => _lv;}
public string Job { get => _job; }
public PlayerInfo(int lv, string job)
{
_lv = lv;
_job = job;
}
}
// CareTaker - 저장된 PlayerInfo를 가지고 있음.
public class SaveInfo
{
private List<PlayerInfo> _playerInfoList = new List<PlayerInfo>();
public List<PlayerInfo> PlayerInfoList { get => _playerInfoList; }
public void Add(PlayerInfo playerInfo)
{
_playerInfoList.Add(playerInfo);
}
}
class Program
{
static void Main(string[] args)
{
Player player = new Player();
SaveInfo saveInfo = new SaveInfo();
// 초보자
player.SetInfo(1, "초보자");
saveInfo.Add(player.Save()); // 저장
player.GetInfo();
Console.WriteLine("\t\t\t -> 레벨업");
// 모험가
player.SetInfo(10, "모험가");
saveInfo.Add(player.Save()); // 저장
player.GetInfo();
// 전사로 전직
player.SetInfo(10, "전사");
saveInfo.Add(player.Save()); // 저장
Console.WriteLine("\t\t\t -> {0} 전직", player.Job);
player.GetInfo();
// 전직 취소
Console.WriteLine("\t\t\t -> 전직 이전 상태로 복귀");
player.Undo(saveInfo.PlayerInfoList[1]); // 불러오기
player.GetInfo();
// 마법사로 전직
player.SetInfo(10, "마법사");
saveInfo.Add(player.Save()); // 저장
Console.WriteLine("\t\t\t -> {0} 전직", player.Job);
player.GetInfo();
// 초기화
Console.WriteLine("\t\t\t -> 초기화");
player.Undo(saveInfo.PlayerInfoList[0]);
player.GetInfo();
// 전사 불러오기
Console.WriteLine("\t\t\t -> 전사로 되돌림");
player.Undo(saveInfo.PlayerInfoList[2]);
player.GetInfo();
Console.WriteLine();
}
}
}
- 실행 결과
<참고 사이트>