스택큐힙리스트

Visitor 패턴: “구조는 그대로, 기능은 덧붙여” 본문

개발

Visitor 패턴: “구조는 그대로, 기능은 덧붙여”

스택큐힙리스트 2025. 7. 30. 16:26
반응형

객체 트리(파일 시스템, 문서 AST, UI 컴포넌트…)에 새로운 연산을 넣어야 할 때, 모든 클래스에 메서드를 추가하자니 코드가 산으로 가고, 상속도 이미 꽉 차 있다면?
Visitor 패턴은 데이터 구조(Elements) 와 알고리즘(Visitors) 을 분리해 “클래스 손대지 않고 기능만 플러그인” 할 수 있게 해 줍니다.

언제 쓰면 딱일까?

  • 컴파일러·파서: 구문 트리를 돌며 타입 체크, 코드 생성, pretty print 등 다양한 작업 추가
  • UI 테스트 자동화: 위젯 트리를 방문하며 스냅샷·접근성 검사·통계 수집
  • 파일 탐색기: 디렉터리·파일 객체 구조에 압축, 용량 계산, 권한 검사 등 추가 기능 삽입
  • 게임 엔진: 씬 그래프에 충돌 검사, 렌더링, AI 패스 한 번에 붙이기
  • 로그·모니터링: 객체 계층을 돌며 메트릭을 추출해 Grafana 로 전송

핵심은 Element 쪽엔 accept(visitor) 한 줄만 두고, 나머지 모든 연산은 Visitor 서브클래스에서 해결한다는 것!

Kotlin 미니 예제 – 파일 시스템 용량 계산

// --- Element 계층 ---
interface FsNode { fun accept(v: FsVisitor) }
class File(val size: Long) : FsNode {
    override fun accept(v: FsVisitor) = v.visitFile(this)
}
class Folder(val children: List<FsNode>) : FsNode {
    override fun accept(v: FsVisitor) = v.visitFolder(this)
}

// --- Visitor 계층 ---
interface FsVisitor {
    fun visitFile(file: File)
    fun visitFolder(folder: Folder)
}

class SizeCalculatorVisitor : FsVisitor {
    var total: Long = 0
        private set
    override fun visitFile(file: File) { total += file.size }
    override fun visitFolder(folder: Folder) { folder.children.forEach { it.accept(this) } }
}

// --- 사용 ---
val tree = Folder(
    listOf(
        File(1200),
        Folder(listOf(File(800), File(400)))
    )
)

val calc = SizeCalculatorVisitor()
tree.accept(calc)
println("총 용량: ${calc.total} bytes")  // 2,400 bytes

새로운 기능(예: 파일 암호화 Visitor)을 추가해도 File·Folder 클래스는 전혀 수정하지 않습니다. 구조와 연산이 완벽히 분리됐기 때문이죠.

테스트 스케치

@Test
fun `Visitor가 모든 노드를 방문해 용량을 합산한다`() {
    val root = Folder(listOf(File(10), Folder(listOf(File(20)))))
    val v = SizeCalculatorVisitor().also { root.accept(it) }
    assertEquals(30, v.total)
}

장 점 vs 단 점

  • 👍 기능 추가 OCP: 새 Visitor 만들면 끝—Element는 건드리지 않는다.
  • 👍 행위 집중: 관련 로직이 Visitor 내부에 모여 읽기·테스트가 쉽다.
  • 👎 Element 변경 ↑ 비용: Element 타입이 자주 바뀌면 모든 Visitor에 메서드 추가해야 함.
  • 👎 이중 디스패치: accept → visitX 구조가 처음엔 낯설 수 있다.

한 줄 요약

Visitor 패턴은 “데이터 구조 위를 돌아다니며 기능을 꽂아 넣는 만능 플러그”—클래스를 건드리지 않고도 행동을 무한히 확장할 수 있다!

반응형
Comments