1. 메멘토 패턴(Memento Pattern)
메멘토 패턴은 캡슐화를 위배하지 않으면서 인스턴스의 상태를 저장하거나 이전 상태로 복원할 수 있게 해주는 패턴 입니다. 인스턴스를 복원하기 위해서는 인스턴스 내부 정보에 접근해야 하지만 접근이 제한된 부분까지 접근을 허용한다면 캡슐화가 파괴될 수 있습니다. 메멘토 패턴은 캡슐화가 파괴되지 않고 인스턴스 상태를 복원할 수 있도록 해줍니다.
메멘토 패턴으로 상태를 저장하는 코드를 작성해 보겠습니다.
Originator.java: Originator는 메멘토를 생성하여 현재 상태를 저장하고 내부 상태를 복구하는 객체입니다. Originator 객체 이외의 객체는 메멘토 객체에 접근하지 못합니다.
Memento.java: Memento는 Originator 객체의 내부 상태를 저장하는 객체입니다.
CareTaker.java: CareTaker는 메멘토를 보관하지만 메멘토의 내용을 확인하거나 처리를 하지는 않습니다.
Client.java: originator 객체의 상태가 변했을때 메멘토를 생성하여 careTaker에 저장합니다. 메멘토를 설정함으로써 이전 상태로 복구될 수 있습니다.
2. 템플릿 메소드 패턴(Template Method Pattern)
템플릿 메소드 패턴은 알고리즘의 구조를 메소드에 정의하고, 하위 클래스에서 알고리즘 구조의 변경없이 알고리즘을 재정의 하는 패턴입니다. 상속을 통해 부모 클래스의 기능을 확장할 때 사용하는 가장 대표적인 방법으로, 객체지향 언어로 개발을 한다면 무의식적으로 사용하는 패턴입니다. 변하지 않는 기능은 부모 클래스에, 자주 변경되며 확장할 기능은 자식 클래스에 생성합니다.
이전에 데코레이터 패턴에서 작성한 라면끓이기 시나리오를 통해 템플릿 메소드 코드를 작성해 보겠습니다.
Ramen.java: 라면의 추상 클래스 입니다. 퍼샤드 패턴으로 make 메소드를 실행시 라면을 끓이는 메커니즘이 순차적으로 실행됩니다. 물을 끓이고 면을 넣고 3분을 기다리는 메커니즘은 공통된 메커니즘으로 부모 클래스인 Ramen에 작성합니다.
CheeseRamen.java:
KimchiRamen.java:
SeafoodRamen.java:
김치라면, 치즈라면, 해물라면은 들어가는 재료가 다르므로 자식 클래스에 작성합니다. 객체지향에 조금 위배되지만 예제 코드이므로 위와 같이 라면의 종류에 따라 클래스를 작성했습니다.
Main.java: 각 라면의 객체를 만들고, make 메소드를 통해 라면을 끓이는 메커니즘을 실행합니다.
출력해보니 라면스프를 빼었네요.. 어찌되었든 각종 라면 끓이기 매커니즘이 출력되었습니다!
템플릿 메소드 패턴은 중복된 코드를 줄일 수 있으며, 알고리즘 구조의 변경 없이 알고리즘을 재정의 할 수 있습니다. 반면에 추상 메소드가 많아지면 클래스 관리가 복잡해지는 단점이 있습니다.
3. 방문자 패턴(Visitor Pattern)
방문자 패턴은 데이터 구조와 처리를 분리하는 패턴입니다. 처리를 담당하는 방문자가 데이터 구조(방문공간)를 돌아다니면서 데이터 처리를 합니다. 즉, 방문공간 객체가 방문자에게 처리를 위임하는 형태가 됩니다.
Visitor는 방문자 클래스의 인터페이스이며, ConcreteElement 클래스에 대한 visit 메소드를 선언합니다. ConcreteVisitor는 Visitor 인터페이스를 구현한 클래스이며, ConcreteElement의 역할을 처리합니다. Element는 방문장소를 나타내며, 방문자를 받아들이는 accept 메소드를 정의하고 있습니다. ConcreteElement는 Element 인터페이스를 구현합니다. ObjectStructure는 Element를 나열하고 방문자로 하여금 Element에 접급하게 하는 인터페이스를 제공합니다. 리스트나 집합 같은 컬렉션이 될 수도 있으며, 컴포지트 패턴의 복합 객체일 수도 있습니다.
예제 코드를 작성하겠습니다. 폴더를 순회하면서 디렉토리와 파일 이름을 출력하는 시나리오 입니다.
Visitor.java: 방문자 인터페이스 입니다. 파일과 디렉토리 객체를 방문하는 visit 메소드를 정의합니다.
ViewVisitor.java: 방문자 인터페이스를 구현한 클래스 입니다. visit 메소드를 통해 방문 장소의 처리를 위임 받습니다.
Element.java: 방문장소 인터페이스 입니다. 방문자를 참조하는 accpet 메소드를 정의합니다.
Entry.java: 방문장소인 엔트리의 추상 클래스 입니다.
File.java: 엔트리를 구현한 파일 클래스 입니다.
Directory.java: 마찬가지로 엔트리를 구현한 디렉토리 클래스 입니다. 컴포지트 패턴을 통해 엔트리 복합체를 형성하고 있습니다.
Main.java:
root, home, pi 디렉토리를 만들고 add 메소드를 통해 root/home/pi/ 형태로 depth를 설정합니다. file1, file2, file3 객체도 만들어서 pi 폴더에 넣어줍니다.
방문자를 만들어서 루트부터 방문하면 순차적으로 모든 엔트리를 방문하면서 경로를 출력합니다.
방문자 패턴은 예제와 같이 트리 형태의 복잡한 자료구조를 순회할 때 사용하면 좋습니다. 이 패턴은 데이터와 알고리즘이 분리되어 데이터의 독립성을 증가 시킬 수 있다는 장점이 있는 반면에 방문자의 visit 메소드와 Element(방문장소)의 accept 메소드가 상호 의존하고 있으므로 결합도가 커진다는 단점이 있습니다. |