티스토리 뷰
데이터 구조 안에 많은 요소가 저장되어 있고, 그 각 요소에 대해서 무엇인가 ‘처리'해 간다고 가정하자.
이때 그 ‘처리'의 코드는 어디에 써야 할까?
일반적으로 생각하면 데이터 구조를 표시하고 있는 클래스 안에 기술할 것이다.
그러나 만약 그 ‘처리'가 여러 종류라면 새로운 처리가 필요할 때마다 데이터 구조의 클래스를 수정해야 한다.
비지터 패턴은 데이터 구조와 처리를 분리한다.
그리고 데이터 구조 안을 돌아다니는 주체인 ‘방문자'를 나타내는 클래스를 준비해서 그 클래스에게 처리를 위임한다.
그렇다면 새로운 처리를 추가하고 싶을 때에는 새로운 ‘방문자'를 만들면 된다.
그리고 데이터 구조는 문을 두드리고 있는 ‘방문자'를 받아들이면 된다.
방문자가 돌아다니는 데이터 구조로 Composite 패턴의 예제 코드를 차용한다.
다음 링크는 Visitor 패턴의 예제 코드다.
Visitor 패턴의 등장인물
Visitor(방문자)의 역할 - Visitor
데이터 구조의 구체적인 요소마다 ‘xxxx을 방문했다'라는 visit(xxxx) 메서드를 선언한다.
visit(xxx)는 xxxx를 처리하기 위한 메서드다.
ConcreteVisitor(구체적인 방문자)의 역할 - ListVisitor
Visitor 역할의 인터페이스(API)를 구현한다.
visit(xxxx)라는 형태의 메서드를 구현하고, 각각의 ConcreteElement 역할의 처리를 기술한다.
Element(요소)의 역할 - Element
Visitor 역할의 방문할 곳을 나타내는 역할로, 방문자를 받아들이는 accept 메서드를 선언한다.
ConcreteElement(구체적인 요소)의 역할 - File, Directory
Element 역할의 인터페이스(API)를 구현하는 역할
ObjectStructure(오브젝트의 구조)의 역할 - Directory
Element 역할의 집합을 취급하는 역할
ConcreteVisitor 역할이 각각의 Element 역할을 취급할 수 있는 메서드를 구비하고 있다.
더블 디스패치
accept(받아들이다) 메서드는 다음과 같이 호출된다.
element.accpet(Visitor)
visit(방문) 메서드는 다음과 같이 호출된다.
visitor.visit(element)
이 두 가지를 비교해 보면 정확히 반대의 관계에 있음을 알 수 있다.
element는 visitor를 accept하고, visitor는 element를 visit하고 있다.
Visitor 패턴에서는 ConcreteElement 역할과 ConcreteVisitor 역할을 하는 한 쌍에 의해 실제 처리가 결정된다.
이것을 일반적으로 일반 디스패치라고 한다.
🤔
왜 이렇게 복잡한 일을 하지?
Visitor 패턴의 목적은 처리를 데이터 구조에서 분리하는 일이다.
데이터 구조는 요소를 집합으로 정리하거나, 요소 사이를 연결해주는 중요한 역할을 한다.
그러나 구조를 유지하는 것과 구조를 기초로 한 처리를 기술하는 것과는 별개다.
Visitor 패턴은 File 클래스나 Directory 클래스의 부품으로써의 독립성을 높일 수 있다.
만약, 처리 내용을 File 클래스나 Directory 클래스의 메서드로서 프로그램을 작성하면, 새로운 ‘처리’를 추가해서 기능 확장을 할 때마다 File 클래스나 Directory 클래스를 수정해야 한다.
OCP
기능 확장과 수정에 대한 이야기가 나왔으니 OCP가 빠질 수 없다.
OCP 관련 글은 아래 포스팅을 참고하자.
ConcreteVisitor 역할의 추가는 간단하다
구체적인 처리는 ConcreteVisitor 역할에 맡길 수 있고, 그 처리를 위한 ConcreteElement 역할을 수정할 필요는 전혀 없기 때문이다.
ConcreteElement 역할의 추가는 곤란하다
예제 프로그램에서 Entry 클래스의 하위 클래스로 Device 클래스를 추가한다고 가정해보자.
Device 클래스는 File 클래스와 Directory 클래스의 형제에 해당한다.
이 때 Visitor 클래스에는 visitor(Device) 메서드를 만들어야 한다.
그리고 Visitor 클래스의 하위 클래스 전부에 새로운 visitor(Device) 메서드를 구현해야 한다.
🤔
Visitor가 처리하기 위해서는 무엇이 필요한가?
Visitor 패턴에서는 데이터 구조의 요소에 대한 처리를 따로 분리해서 Visitor 역할에게 맡긴다.
이렇게 해서 데이터 구조와 요소에 대한 처리를 분리할 수 있다.
Element 역할은 Visitor 역할에 대해서 충분한 정보를 공개할 필요가 있다.
예제 프로그램에서는 visitor(Directory) 안에 각각의 디렉터리 엔트리에 대해 accept를 실행한다.
이와 같은 처리를 실현하기 위해서 Directory가 ‘각각의 디렉터리 엔트리를 얻기'위한 iterator 메서드를 제공할 필요가 있다.
방문자는 데이터 구조에서 필요한 정보를 취득해서 동작한다.
필요한 정보를 얻을 수 없으면 방문자는 제대로 일할 수 없다.
반면에 공개할 필요 없는 정보까지 공개하면 미래의 데이터 구조를 개량하기 어렵게 된다.
관련 패턴
- Iterator 패턴
- Composite 패턴
- Interpreter 패턴
'JAVA > 디자인 패턴' 카테고리의 다른 글
파사드(Facade) 패턴 (0) | 2022.03.31 |
---|---|
책임 떠넘기기(Chain of Responsibility) 패턴 (0) | 2022.03.30 |
데코레이터(Decorator) 패턴 (0) | 2022.03.23 |
컴포지트(Composite) 패턴 (0) | 2022.03.21 |
전략(Strategy) 패턴 (0) | 2022.03.21 |
- Total
- Today
- Yesterday
- 백준
- Java
- BAEKJOON
- 알고리즘
- 정규표현식
- 코테
- 테라폼
- programmers
- MSA
- 클린 코드
- 클린 아키텍처
- Spring Boot
- 프로그래머스
- 이펙티브 자바
- C++
- Effective Java
- Algorithm
- node.js
- Spring
- 디자인 패턴
- JPA
- Kotlin
- 객체지향
- 이팩티브 자바
- 디자인패턴
- Olympiad
- kkoon9
- AWS
- kotest
- BOJ
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |