데이터 구조와 처리를 분리
'처리'가 여러종류라서, 새로운 처리가 필요해질 때 마다, 데이터 구조를 나타내는 클래스 수정해야함
🙋♂️데이터 구조는 문을 두드리는 "방문자" 만 받아들이기만 하면 된다
방문자가 데이터 처리 담당
- 데이터 구조 → "방문자"가 처리
- 새로운 처리 추가 → 새로운 "방문자" 가 만든다
📃 UML
- 방문자
- Visitor (추상클래스) : 파일이나 디렉토리를 방문하는 방문자를 나타낸 추상 클래스
- visit(File or Directory) : File이나 Directory를 방문했을 때 각각 클래스가 호출하는 메소드
- 메소드 오버로드(overload) 이용
- visit 메소드의 이름은 같은데, 인자의 종류가 다름
- ListVisitor : Visitor 클래스의 하위 클래스로 파일이나 디렉토리의 알람을 나타내는 클래스 → ConcreteVisitor
- Visitor 역할의 API 실제로 구현
- 실제 데이터구조(File or Directory)를 옮겨 다니면서 리스트를 출력함
- currentdir 필드
- visit(File)
- File에 대해 수행해야 할 처리가 기술
- algo
- 현재 디렉토리와 File의 toString( ) 반환 값을 연결하여 현재 파일의 전체 경로 출력
- visit(Directory)
- Dir에 대해 수행해야 할 처리가 기술
- algo
- 디렉토리 전체 경로 및 크기 출력
- 현재 디렉토리(currentdir) 임시로 savedir 저장
- currentdir를 입력인자로 들어온 dir로 바꿈
- 입력인자로 들어온 디렉토리의 iterator를 얻는다
- 입력인자로 들어온 dir가 유지하는 원소들을 차례로 방문하면서, accept(this)를 호출하여 방문자가 방문했음을 알린다
- while 루프가 끝나면 currentdir을 원래 dir로 복귀시킨다
- 복잡한 재귀적인 호출
- accept 메소드는 visit 메소드를 호출하고 visit 메소드는 accept 메소드 호출
- 데이터구조
- Element (interface) : Visitor 클래스의 인스턴스를 받아들이는 데이터 구조를 나타내는 인터페이스 → Acceptor
- 방문자를 받아들임 → Visitor 역할이 방문할 장소를 나타내는 역할
- accept(Visitor v) : Visitor 타입을 입력 인자로 받아들임
- Entry (추상클래스) : Element 인터페이스를 구현
- add( )
- Directory 클래스에서만 add( )가 유효하므로, Entry에서는 에러로 처리
- iterator( )
- 요소에 대한 Iterator를 얻을 때 호출되는 메소드
- Directory 클래스에서만 iterator( )가 유효하므로, Entry에서는 에러로 처리
- ConcreteAcceptor → File or Dir
- File : 파일을 나타내는 클래스
- accept(Visitor v) : 클라이언트가 File 객체에게 "방문자를 받아들이세요" 라고 요청할 때 호출하는 메소드
- 클라이언트는 Visitor를 매개변수로 하여 accept 호출
- 입력인자로 들어온 방문자의 visit 메소드 호출
- 현재 자신 객체를 인자로 하여 호출
- Visitor의 visit(File) 메소드 실행
- 즉 방문자가 방문하면 방문자에게 "나는 File 객체입니다. 나의 일을 처리해주세요" 라고 요청하는 것과 비슷
- Directory : 디렉토리를 나타내는 클래스
- iterator( )
- 디렉토리가 유지하고 있는 엔트리들에 대한 Iterator를 반환한다
- accept(Visitor)
- Visitor의 visit(Directory) 메소드 실행
- 즉 방문자가 방문하면 방문자에게 "나는 Directory 객체입니다. 나의 일을 처리해주세요" 라고 요청하는 것과 비슷
- FileTreatmentException : File에 대해서 add한 경우에 발생하는 예외 클래스
Main 클래스
Composite vs Visitor
-
Composite
- main 메소드가 엔트리 리스트를 출력하기 위해 rootdir.printList() 호출
- 엔트리의 내용을 출력하는 책임 → File , Dir 클래스가 가지고 있음
-
Visitor
- main 메소드가 엔트리 리스트를 출력하기 위해 rootdir.accept(new ListVisitor()) 호출
- 엔트리의 내용을 출력하는 책임 → ListVisitor 클래스가 가지고 있음
🤔 왜이렇게 복잡하지?
👉 Visitor 패턴의 목적은 "처리"를 "데이터 구조"로 부터 분리하는 것!
- 다른 처리를 하는 ConcreteVisitor(=ListVisitor)를 추가할 수 있다
- 기존의 ConcreteVisitor 기능 확장
- 부품의 독립성 향상
👩🏫 Open-Closed Principle
- 확장에 대해서는 열려있고 수정에 대해서는 닫혀있음
- 기능 확장 용이 but 기존 클래스 수정할 필요 없어야함
- ConcreteVisitor 역할 추가 간단 but ConcreteElement 역할추가 어려움
- why ? Element → 데이터 구조 따라서 바뀌면 모든 Visitor 내부도 바껴야함