메멘토(Memento) 패턴
디자인 패턴 ·메멘토 패턴은 객체의 상태를 저장하고 복원하기 위해 사용되는 디자인 패턴입니다. 이 패턴은 객체의 상태를 캡슐화하고, 나중에 필요할 때 이 상태를 복원할 수 있는 방법을 제공합니다.
구성 요소
- Originator(원조자): 상태를 저장하고 복원해야 하는 객체를 나타냅니다. 원조자는 현재 상태를 저장하고, 메멘토 객체를 생성하여 상태를 복원하는 역할을 합니다.
- Memento(메멘토): 원조자 객체의 상태를 저장하는 역할을 합니다. 메멘토는 원조자 객체의 상태를 캡슐화하여 저장하고, 필요한 경우에 상태를 복원할 수 있는 인터페이스를 제공합니다.
- Caretaker(관리자): 메멘토 객체를 관리하고, 필요한 시점에서 상태를 복원하는 역할을 합니다. 관리자는 메멘토를 생성하고 저장하며, 필요한 경우에 메멘토를 원조자에게 전달하여 상태를 복원합니다.
구현:
- 원조자 객체는 현재 상태를 저장하기 위해 메멘토 객체를 생성합니다.
- 원조자 객체는 메멘토 객체에 자신의 상태를 저장합니다.
- 원조자 객체는 메멘토 객체를 관리자에게 전달합니다.
- 관리자는 메멘토 객체를 보관하거나 필요한 경우에 복원을 위해 원조자에게 전달합니다.
- 필요한 시점에서 관리자는 메멘토 객체를 원조자에게 전달하여 상태를 복원합니다.
장점
- 상태의 캡슐화: 메멘토 패턴은 객체의 상태를 캡슐화하여 외부에 노출시키지 않고 저장하므로, 객체의 내부 구조나 상태를 보호할 수 있습니다. 이는 정보 은닉(Encapsulation) 원칙을 따르고 객체 간의 결합도를 낮추는 데 도움을 줍니다.
- 상태 복원 기능: 메멘토 패턴은 객체의 상태를 저장하고 필요할 때 복원할 수 있는 기능을 제공합니다. 이는 객체의 이전 상태로 되돌릴 수 있는 “되돌리기” 기능이나 재시작 후 상태 복원 등에 유용합니다.
- 확장성: 메멘토 패턴은 관리자(Caretaker) 객체를 통해 여러 개의 메멘토를 관리하고, 원조자(Originator) 객체의 상태를 여러 단계로 나누어 저장할 수 있습니다. 이는 복잡한 상태 복원이나 다양한 상태 이력을 관리해야 할 때 유용합니다.
단점
- 메모리 사용량 증가: 메멘토 패턴은 객체의 상태를 저장하기 위해 메멘토 객체를 생성하고 관리해야 합니다. 상태의 크기가 크거나 상태를 빈번하게 저장해야 하는 경우에는 메모리 사용량이 증가할 수 있습니다.
- 성능 저하: 메멘토 패턴은 객체의 상태를 저장하고 복원하기 위해 추가적인 작업이 필요합니다. 상태의 저장과 복원 과정이 복잡할 경우, 성능 저하가 발생할 수 있습니다.
- 상태 노출 가능성: 메멘토 패턴을 사용하면 상태를 캡슐화하여 보호할 수 있지만, 관리자 객체가 메멘토 객체를 직접 조작할 수 있다면 상태가 노출될 수 있습니다. 이에 대한 보안 조치가 필요합니다.
예시
홍팀과 청팀이 게임을 해서 점수를 기록한다. 만약 게임 판정이 잘못될 경우 이전 점수 기록으로 되돌려야한다.
Originator
public class Game implements Serializable {
private int redTeamScore;
private int blueTeamScore;
public int getRedTeamScore() {
return redTeamScore;
}
public void setRedTeamScore(int redTeamScore) {
this.redTeamScore = redTeamScore;
}
public int getBlueTeamScore() {
return blueTeamScore;
}
public void setBlueTeamScore(int blueTeamScore) {
this.blueTeamScore = blueTeamScore;
}
public GameSave save() {
return new GameSave(this.redTeamScore, this.blueTeamScore);
}
public void restore(GameSave save) {
this.redTeamScore = save.getRedTeamScore();
this.blueTeamScore = save.getBlueTeamScore();
}
}
Memento
public final class GameSave {
private final int redTeamScore;
private final int blueTeamScore;
public GameSave(int redTeamScore, int blueTeamScore) {
this.redTeamScore = redTeamScore;
this.blueTeamScore = blueTeamScore;
}
public int getRedTeamScore() {
return redTeamScore;
}
public int getBlueTeamScore() {
return blueTeamScore;
}
}
Client
class GameTest {
@Test
public void game_restore_test() {
Game game = new Game();
game.setRedTeamScore(10);
game.setBlueTeamScore(20);
GameSave save = game.save();
game.setRedTeamScore(31);
game.setBlueTeamScore(21);
game.restore(save);
assertEquals(10, game.getRedTeamScore());
assertEquals(20, game.getBlueTeamScore());
}
}
결론
메멘토 패턴은 객체의 상태를 저장하고 복원하기 위한 유용한 디자인 패턴입니다. 이 패턴을 사용하면 객체의 상태를 캡슐화하여 외부에 노출시키지 않고 보호할 수 있으며, 필요한 경우에 상태를 복원할 수 있습니다. 또한, 관리자 객체를 통해 여러 상태를 관리하고 확장성을 확보할 수 있습니다.
하지만 메멘토 패턴을 사용할 때는 메모리 사용량과 성능에 대한 고려가 필요합니다. 상태의 크기가 크거나 저장과 복원 과정이 복잡한 경우에는 메모리 사용량이 증가하고 성능이 저하될 수 있습니다. 또한, 상태 노출 가능성과 관련된 보안 문제에 대해서도 주의가 필요합니다.
예제는 이곳 에서 확인하실수 있습니다.